From bcacd72dade3a3bbe6c8e276cf49b5aaa9d72b1e Mon Sep 17 00:00:00 2001 From: Alexander Tatarinovich Date: Thu, 18 Aug 2016 16:12:38 +0300 Subject: [PATCH 01/31] Bug 3879 - Show language specific sailors info textboxes only on demand Change-Id: I9a2389a1d8f939ea7162c77cf4d8c90ee3ae95d3 --- .../ui/adminconsole/EventCreateDialog.java | 5 - .../gwt/ui/adminconsole/EventDialog.java | 31 ++--- .../gwt/ui/adminconsole/EventEditDialog.java | 86 +++++++------- .../adminconsole/ExternalLinksComposite.java | 109 ++++++++++++++++++ .../sailing/gwt/ui/client/StringMessages.java | 9 ++ .../gwt/ui/client/StringMessages.properties | 11 +- 6 files changed, 178 insertions(+), 73 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExternalLinksComposite.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java index 6ad13ea3c6c..e876fea9cd1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java @@ -37,11 +37,6 @@ public class EventCreateDialog extends EventDialog { endDateBox = createDateTimeBox(now); endDateBox.setFormat("dd/mm/yyyy hh:ii"); endDateBox.ensureDebugId("EndDateTimeBox"); - officialWebsiteURLEntryField = createTextBox(null); - officialWebsiteURLEntryField.setVisibleLength(50); - baseURLEntryField = createTextBox(null); - baseURLEntryField.setVisibleLength(50); - sailorsInfoWebsiteURLEntryFields = createTextBoxesForLocalesAndDefault(Collections. emptyMap()); isPublicCheckBox = createCheckbox(""); isPublicCheckBox.setValue(false); isPublicCheckBox.ensureDebugId("IsPublicCheckBox"); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index adadf4aae41..8be2dcc7ee8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java @@ -48,14 +48,12 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap protected BetterDateTimeBox endDateBox; protected CheckBox isPublicCheckBox; protected UUID id; - protected TextBox officialWebsiteURLEntryField; - protected TextBox baseURLEntryField; - protected Map sailorsInfoWebsiteURLEntryFields = new HashMap<>(); protected CourseAreaListInlineEditorComposite courseAreaNameList; protected StringConstantsListEditorComposite leaderboardGroupList; protected Map availableLeaderboardGroupsByName; protected ImagesListComposite imagesListComposite; protected VideosListComposite videosListComposite; + protected ExternalLinksComposite externalLinksComposite; protected static class EventParameterValidator implements Validator { @@ -162,6 +160,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap imagesListComposite = new ImagesListComposite(sailingService, stringMessages); videosListComposite = new VideosListComposite(stringMessages); + externalLinksComposite = new ExternalLinksComposite(stringMessages); } @Override @@ -176,13 +175,9 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap } result.setName(nameEntryField.getText()); result.setDescription(descriptionEntryField.getText()); - result.setOfficialWebsiteURL(officialWebsiteURLEntryField.getText().trim().isEmpty() ? null : officialWebsiteURLEntryField.getText().trim()); - result.setBaseURL(baseURLEntryField.getText().trim().isEmpty() ? null : baseURLEntryField.getText().trim()); - for (Map.Entry sailorsInfoWebsiteUrlEntry : sailorsInfoWebsiteURLEntryFields.entrySet()) { - TextBox sailorsInfoWebsiteURLEntryField = sailorsInfoWebsiteUrlEntry.getValue(); - String sailorsInfoWebsiteURL = sailorsInfoWebsiteURLEntryField.getText().trim(); - result.setSailorsInfoWebsiteURL(sailorsInfoWebsiteUrlEntry.getKey(), sailorsInfoWebsiteURL.isEmpty() ? null : sailorsInfoWebsiteURLEntryField.getText().trim()); - } + result.setOfficialWebsiteURL(externalLinksComposite.getOfficialWebsiteURLValue()); + result.setBaseURL(externalLinksComposite.getBaseURLValue()); + result.setSailorsInfoWebsiteURLs(externalLinksComposite.getSailorsInfoWebsiteURLs()); result.startDate = startDateBox.getValue(); result.endDate = endDateBox.getValue(); result.isPublic = isPublicCheckBox.getValue(); @@ -206,7 +201,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap if (additionalWidget != null) { panel.add(additionalWidget); } - Grid formGrid = new Grid(10 + GWTLocaleUtil.getLanguageCountWithDefault(), 2); + Grid formGrid = new Grid(7, 2); int rowIndex = 0; formGrid.setWidget(rowIndex, 0, new Label(stringMessages.name() + ":")); formGrid.setWidget(rowIndex++, 1, nameEntryField); @@ -222,17 +217,6 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap formGrid.setWidget(rowIndex++, 1, endDateBox); formGrid.setWidget(rowIndex, 0, new Label(stringMessages.isPublic() + ":")); formGrid.setWidget(rowIndex++, 1, isPublicCheckBox); - formGrid.setWidget(rowIndex, 0, new Label(stringMessages.eventOfficialWebsiteURL() + ":")); - formGrid.setWidget(rowIndex++, 1, officialWebsiteURLEntryField); - formGrid.setWidget(rowIndex, 0, new Label(stringMessages.eventBaseURL() + ":")); - formGrid.setWidget(rowIndex++, 1, baseURLEntryField); - for (Map.Entry sailorsInfoWebsiteUrlEntry : sailorsInfoWebsiteURLEntryFields.entrySet()) { - String suffix = " ["+ (sailorsInfoWebsiteUrlEntry.getKey() == null ? stringMessages.defaultLocale() + "*" : sailorsInfoWebsiteUrlEntry.getKey()) + "]"; - formGrid.setWidget(rowIndex, 0, new Label(stringMessages.eventSailorsInfoWebsiteURL() + suffix + ":")); - formGrid.setWidget(rowIndex, 1, sailorsInfoWebsiteUrlEntry.getValue()); - rowIndex++; - } - formGrid.setText(rowIndex, 1, "[*] " + stringMessages.defaultSailorsInfoLinkInfoText()); TabLayoutPanel tabPanel = new TabLayoutPanel(30, Unit.PX); tabPanel.ensureDebugId("EventDialogTabs"); tabPanel.setHeight("525px"); @@ -240,6 +224,9 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap final ScrollPanel eventTab = new ScrollPanel(formGrid); eventTab.ensureDebugId("EventTab"); tabPanel.add(eventTab, stringMessages.event()); + final ScrollPanel externalLinksCompositeTab = new ScrollPanel(externalLinksComposite); + externalLinksCompositeTab.ensureDebugId("ExternalLinksCompositeTab"); + tabPanel.add(externalLinksCompositeTab, stringMessages.externalLinks()); final ScrollPanel leaderboardGroupTab = new ScrollPanel(leaderboardGroupList); leaderboardGroupTab.ensureDebugId("LeaderboardGroupsTab"); tabPanel.add(leaderboardGroupTab, stringMessages.leaderboardGroups()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java index a426618a9bd..17417c93cdb 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java @@ -1,45 +1,41 @@ -package com.sap.sailing.gwt.ui.adminconsole; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import com.sap.sailing.gwt.ui.client.SailingServiceAsync; -import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sailing.gwt.ui.shared.EventDTO; -import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; - -public class EventEditDialog extends EventDialog { - public EventEditDialog(EventDTO event, Collection otherExistingEvents, List availableLeaderboardGroups, - SailingServiceAsync sailingService, StringMessages stringMessages, DialogCallback callback) { - super(new EventParameterValidator(stringMessages, otherExistingEvents), sailingService, stringMessages, availableLeaderboardGroups, event.getLeaderboardGroups(), callback); - nameEntryField = createTextBox(event.getName()); - nameEntryField.setVisibleLength(50); - descriptionEntryField = createTextArea(event.getDescription()); - descriptionEntryField.setCharacterWidth(50); - descriptionEntryField.setVisibleLines(2); - descriptionEntryField.getElement().getStyle().setProperty("resize", "none"); - venueEntryField = createTextBox(event.venue.getName()); - venueEntryField.setVisibleLength(35); - startDateBox = createDateTimeBox(event.startDate); - startDateBox.setFormat("dd/mm/yyyy hh:ii"); - endDateBox = createDateTimeBox(event.endDate); - endDateBox.setFormat("dd/mm/yyyy hh:ii"); - isPublicCheckBox = createCheckbox(""); - isPublicCheckBox.setValue(event.isPublic); - id = event.id; - officialWebsiteURLEntryField = createTextBox(event.getOfficialWebsiteURL()); - officialWebsiteURLEntryField.setVisibleLength(50); - baseURLEntryField = createTextBox(event.getBaseURL()); - baseURLEntryField.setVisibleLength(50); - sailorsInfoWebsiteURLEntryFields = createTextBoxesForLocalesAndDefault(event.getSailorsInfoWebsiteURLs()); - courseAreaNameList.setValue(new ArrayList<>(event.venue.getCourseAreas())); - List leaderboardGroupNames = new ArrayList<>(); - for(LeaderboardGroupDTO leaderboardGroupDTO: event.getLeaderboardGroups()) { - leaderboardGroupNames.add(leaderboardGroupDTO.getName()); - } - leaderboardGroupList.setValue(leaderboardGroupNames); - imagesListComposite.fillImages(event.getImages()); - videosListComposite.fillVideos(event.getVideos()); - } -} +package com.sap.sailing.gwt.ui.adminconsole; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import com.sap.sailing.gwt.ui.client.SailingServiceAsync; +import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; + +public class EventEditDialog extends EventDialog { + public EventEditDialog(EventDTO event, Collection otherExistingEvents, List availableLeaderboardGroups, + SailingServiceAsync sailingService, StringMessages stringMessages, DialogCallback callback) { + super(new EventParameterValidator(stringMessages, otherExistingEvents), sailingService, stringMessages, availableLeaderboardGroups, event.getLeaderboardGroups(), callback); + nameEntryField = createTextBox(event.getName()); + nameEntryField.setVisibleLength(50); + descriptionEntryField = createTextArea(event.getDescription()); + descriptionEntryField.setCharacterWidth(50); + descriptionEntryField.setVisibleLines(2); + descriptionEntryField.getElement().getStyle().setProperty("resize", "none"); + venueEntryField = createTextBox(event.venue.getName()); + venueEntryField.setVisibleLength(35); + startDateBox = createDateTimeBox(event.startDate); + startDateBox.setFormat("dd/mm/yyyy hh:ii"); + endDateBox = createDateTimeBox(event.endDate); + endDateBox.setFormat("dd/mm/yyyy hh:ii"); + isPublicCheckBox = createCheckbox(""); + isPublicCheckBox.setValue(event.isPublic); + id = event.id; + courseAreaNameList.setValue(new ArrayList<>(event.venue.getCourseAreas())); + List leaderboardGroupNames = new ArrayList<>(); + for(LeaderboardGroupDTO leaderboardGroupDTO: event.getLeaderboardGroups()) { + leaderboardGroupNames.add(leaderboardGroupDTO.getName()); + } + leaderboardGroupList.setValue(leaderboardGroupNames); + imagesListComposite.fillImages(event.getImages()); + videosListComposite.fillVideos(event.getVideos()); + externalLinksComposite.fillExternalLinks(event); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExternalLinksComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExternalLinksComposite.java new file mode 100644 index 00000000000..a5b770a3994 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExternalLinksComposite.java @@ -0,0 +1,109 @@ +package com.sap.sailing.gwt.ui.adminconsole; + +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.Grid; + +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sse.gwt.client.GWTLocaleUtil; + +public class ExternalLinksComposite extends Composite { + + private Map sailorsInfoWebsiteURLEntryFields = new HashMap<>(); + private TextBox officialWebsiteURLEntryField; + private TextBox baseURLEntryField; + + private StringMessages stringMessages; + + public ExternalLinksComposite(StringMessages stringMessages) { + this.stringMessages = stringMessages; + + officialWebsiteURLEntryField = new TextBox(); + officialWebsiteURLEntryField.setVisibleLength(50); + baseURLEntryField = new TextBox(); + baseURLEntryField.setVisibleLength(50); + sailorsInfoWebsiteURLEntryFields = createTextBoxesForLocalesAndDefault(Collections. emptyMap()); + + int rowIndex = 0; + Grid formGrid = new Grid(GWTLocaleUtil.getLanguageCountWithDefault() + 3, 2); + formGrid.setWidget(rowIndex, 0, new Label(stringMessages.eventOfficialWebsiteURL() + ":")); + formGrid.setWidget(rowIndex++, 1, officialWebsiteURLEntryField); + formGrid.setWidget(rowIndex, 0, new Label(stringMessages.eventBaseURL() + ":")); + formGrid.setWidget(rowIndex++, 1, baseURLEntryField); + Map languageByLocaleMap = getLanguageByLocaleMap(); + for (Map.Entry sailorsInfoWebsiteUrlEntry : sailorsInfoWebsiteURLEntryFields.entrySet()) { + String locale = sailorsInfoWebsiteUrlEntry.getKey(); + String suffix = " [" + (locale == null ? stringMessages.defaultLocale() + "*" : locale) + "]"; + formGrid.setWidget(rowIndex, 0, new Label( + stringMessages.eventLocaleSailorsInfoWebsiteURL(languageByLocaleMap.get(locale)) + suffix + ":")); + formGrid.setWidget(rowIndex, 1, sailorsInfoWebsiteUrlEntry.getValue()); + rowIndex++; + } + + VerticalPanel panel = new VerticalPanel(); + panel.setWidth("100%"); + panel.add(formGrid); + panel.add(new Label("[*] " + stringMessages.defaultSailorsInfoLinkInfoText())); + initWidget(panel); + } + + public String getOfficialWebsiteURLValue() { + String value = officialWebsiteURLEntryField.getText().trim(); + return value.isEmpty() ? null : value; + } + + public String getBaseURLValue() { + String value = baseURLEntryField.getText().trim(); + return value.isEmpty() ? null : value; + } + + public Map getSailorsInfoWebsiteURLs() { + Map sailorsInfoWebsiteURLsMap = new HashMap<>(); + for (Map.Entry sailorsInfoWebsiteUrlEntry : sailorsInfoWebsiteURLEntryFields.entrySet()) { + TextBox sailorsInfoWebsiteURLEntryField = sailorsInfoWebsiteUrlEntry.getValue(); + String sailorsInfoWebsiteURL = sailorsInfoWebsiteURLEntryField.getText().trim(); + sailorsInfoWebsiteURLsMap.put(sailorsInfoWebsiteUrlEntry.getKey(), + sailorsInfoWebsiteURL.isEmpty() ? null : sailorsInfoWebsiteURL); + } + return sailorsInfoWebsiteURLsMap; + } + + public void fillExternalLinks(EventDTO event) { + Map initialValues = event.getSailorsInfoWebsiteURLs(); + for (String localeName : GWTLocaleUtil.getAvailableLocalesAndDefault()) { + sailorsInfoWebsiteURLEntryFields.get(localeName).setValue(initialValues.get(localeName)); + } + officialWebsiteURLEntryField.setValue(event.getOfficialWebsiteURL()); + baseURLEntryField.setValue(event.getBaseURL()); + } + + private Map createTextBoxesForLocalesAndDefault(Map initialValues) { + Map result = new LinkedHashMap<>(); + for (String localeName : GWTLocaleUtil.getAvailableLocalesAndDefault()) { + TextBox sailorsInfoWebsiteURLEntryField = new TextBox(); + sailorsInfoWebsiteURLEntryField.setValue(initialValues.get(localeName)); + sailorsInfoWebsiteURLEntryField.setVisibleLength(50); + result.put(localeName, sailorsInfoWebsiteURLEntryField); + } + return result; + } + + private Map getLanguageByLocaleMap() { + Map languageByLocaleMap = new HashMap<>(); + languageByLocaleMap.put(null, stringMessages.unspecified()); + languageByLocaleMap.put("en", stringMessages.english()); + languageByLocaleMap.put("de", stringMessages.german()); + languageByLocaleMap.put("ja", stringMessages.japanese()); + languageByLocaleMap.put("ru", stringMessages.russian()); + languageByLocaleMap.put("zh", stringMessages.сhinese()); + return languageByLocaleMap; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 12b39f997ba..aa74584c3e0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -1635,4 +1635,13 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String favoriteBoatClasses(); String notificationAboutNewResults(); String notificationAboutUpcomingRaces(); + String defineLanguageSpecificURLs(); + String eventLocaleSailorsInfoWebsiteURL(String language); + String externalLinks(); + String unspecified(); + String english(); + String german(); + String russian(); + String japanese(); + String сhinese(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 600193f46b7..a0528a747a8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -1607,4 +1607,13 @@ watchLive=Watch live raceAnalysis=Race analysis startAnalysis=Start analysis winningLanes=Winning lanes -maximumNumberOfDiscards=Maximum number of discards \ No newline at end of file +maximumNumberOfDiscards=Maximum number of discards +defineLanguageSpecificURLs=Define language specific URLs +externalLinks=External links +eventLocaleSailorsInfoWebsiteURL=URL for {0} language +unspecified=unspecified +english=english +german=german +russian=russian +japanese=japanese +сhinese=сhinese \ No newline at end of file From 0282e89be48abb61eb8e6e406468d542f4618e14 Mon Sep 17 00:00:00 2001 From: Alexander Tatarinovich Date: Thu, 8 Sep 2016 10:42:02 +0300 Subject: [PATCH 02/31] Bug 3879: Remove messages and unused method Change-Id: I5145055f378ecbd7066e3b6fa3556f50a9ad48cc --- .../sap/sailing/gwt/ui/adminconsole/EventDialog.java | 12 ------------ .../sap/sailing/gwt/ui/client/StringMessages.java | 1 - .../sailing/gwt/ui/client/StringMessages.properties | 1 - 3 files changed, 14 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index 8be2dcc7ee8..95e3d4e34a4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java @@ -5,7 +5,6 @@ import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.UUID; @@ -32,7 +31,6 @@ import com.sap.sailing.gwt.ui.shared.CourseAreaDTO; import com.sap.sailing.gwt.ui.shared.EventDTO; import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; import com.sap.sailing.gwt.ui.shared.VenueDTO; -import com.sap.sse.gwt.client.GWTLocaleUtil; import com.sap.sse.gwt.client.IconResources; import com.sap.sse.gwt.client.controls.listedit.GenericStringListInlineEditorComposite; import com.sap.sse.gwt.client.controls.listedit.StringConstantsListEditorComposite; @@ -246,14 +244,4 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap protected FocusWidget getInitialFocusWidget() { return nameEntryField; } - - protected Map createTextBoxesForLocalesAndDefault(Map initialValues) { - Map result = new LinkedHashMap<>(); - for(String localeName : GWTLocaleUtil.getAvailableLocalesAndDefault()) { - TextBox sailorsInfoWebsiteURLEntryField = createTextBox(initialValues.get(localeName)); - sailorsInfoWebsiteURLEntryField.setVisibleLength(50); - result.put(localeName, sailorsInfoWebsiteURLEntryField); - } - return result; - } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index aa74584c3e0..20cca3cab05 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -1635,7 +1635,6 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String favoriteBoatClasses(); String notificationAboutNewResults(); String notificationAboutUpcomingRaces(); - String defineLanguageSpecificURLs(); String eventLocaleSailorsInfoWebsiteURL(String language); String externalLinks(); String unspecified(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index a0528a747a8..c23a0a7eaa8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -1608,7 +1608,6 @@ raceAnalysis=Race analysis startAnalysis=Start analysis winningLanes=Winning lanes maximumNumberOfDiscards=Maximum number of discards -defineLanguageSpecificURLs=Define language specific URLs externalLinks=External links eventLocaleSailorsInfoWebsiteURL=URL for {0} language unspecified=unspecified From fdbc8ef75615955a0d79df5310dff1791fb1e031 Mon Sep 17 00:00:00 2001 From: Alexander Tatarinovich Date: Thu, 8 Sep 2016 10:56:53 +0300 Subject: [PATCH 03/31] Bug3879: correct line delimiters Change-Id: I419d0b344fa83f99573db669df3290a3fd84088e --- .../gwt/ui/adminconsole/EventEditDialog.java | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java index 17417c93cdb..036440cef6b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java @@ -1,41 +1,41 @@ -package com.sap.sailing.gwt.ui.adminconsole; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import com.sap.sailing.gwt.ui.client.SailingServiceAsync; -import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sailing.gwt.ui.shared.EventDTO; -import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; - -public class EventEditDialog extends EventDialog { - public EventEditDialog(EventDTO event, Collection otherExistingEvents, List availableLeaderboardGroups, - SailingServiceAsync sailingService, StringMessages stringMessages, DialogCallback callback) { - super(new EventParameterValidator(stringMessages, otherExistingEvents), sailingService, stringMessages, availableLeaderboardGroups, event.getLeaderboardGroups(), callback); - nameEntryField = createTextBox(event.getName()); - nameEntryField.setVisibleLength(50); - descriptionEntryField = createTextArea(event.getDescription()); - descriptionEntryField.setCharacterWidth(50); - descriptionEntryField.setVisibleLines(2); - descriptionEntryField.getElement().getStyle().setProperty("resize", "none"); - venueEntryField = createTextBox(event.venue.getName()); - venueEntryField.setVisibleLength(35); - startDateBox = createDateTimeBox(event.startDate); - startDateBox.setFormat("dd/mm/yyyy hh:ii"); - endDateBox = createDateTimeBox(event.endDate); - endDateBox.setFormat("dd/mm/yyyy hh:ii"); - isPublicCheckBox = createCheckbox(""); - isPublicCheckBox.setValue(event.isPublic); - id = event.id; - courseAreaNameList.setValue(new ArrayList<>(event.venue.getCourseAreas())); - List leaderboardGroupNames = new ArrayList<>(); - for(LeaderboardGroupDTO leaderboardGroupDTO: event.getLeaderboardGroups()) { - leaderboardGroupNames.add(leaderboardGroupDTO.getName()); - } - leaderboardGroupList.setValue(leaderboardGroupNames); - imagesListComposite.fillImages(event.getImages()); - videosListComposite.fillVideos(event.getVideos()); - externalLinksComposite.fillExternalLinks(event); - } -} +package com.sap.sailing.gwt.ui.adminconsole; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import com.sap.sailing.gwt.ui.client.SailingServiceAsync; +import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; + +public class EventEditDialog extends EventDialog { + public EventEditDialog(EventDTO event, Collection otherExistingEvents, List availableLeaderboardGroups, + SailingServiceAsync sailingService, StringMessages stringMessages, DialogCallback callback) { + super(new EventParameterValidator(stringMessages, otherExistingEvents), sailingService, stringMessages, availableLeaderboardGroups, event.getLeaderboardGroups(), callback); + nameEntryField = createTextBox(event.getName()); + nameEntryField.setVisibleLength(50); + descriptionEntryField = createTextArea(event.getDescription()); + descriptionEntryField.setCharacterWidth(50); + descriptionEntryField.setVisibleLines(2); + descriptionEntryField.getElement().getStyle().setProperty("resize", "none"); + venueEntryField = createTextBox(event.venue.getName()); + venueEntryField.setVisibleLength(35); + startDateBox = createDateTimeBox(event.startDate); + startDateBox.setFormat("dd/mm/yyyy hh:ii"); + endDateBox = createDateTimeBox(event.endDate); + endDateBox.setFormat("dd/mm/yyyy hh:ii"); + isPublicCheckBox = createCheckbox(""); + isPublicCheckBox.setValue(event.isPublic); + id = event.id; + courseAreaNameList.setValue(new ArrayList<>(event.venue.getCourseAreas())); + List leaderboardGroupNames = new ArrayList<>(); + for(LeaderboardGroupDTO leaderboardGroupDTO: event.getLeaderboardGroups()) { + leaderboardGroupNames.add(leaderboardGroupDTO.getName()); + } + leaderboardGroupList.setValue(leaderboardGroupNames); + imagesListComposite.fillImages(event.getImages()); + videosListComposite.fillVideos(event.getVideos()); + externalLinksComposite.fillExternalLinks(event); + } +} From 975d6b911abf994cb9d97a9085bf8532f33d261c Mon Sep 17 00:00:00 2001 From: Alexander Tatarinovich Date: Mon, 12 Sep 2016 12:57:35 +0300 Subject: [PATCH 04/31] Bug 3879: review fix Change-Id: Ib6be1bb3cdb8550c577ab1f7b31832d2f5b7fc5f --- .../ui/adminconsole/EventCreateDialog.java | 2 ++ .../gwt/ui/adminconsole/EventDialog.java | 7 ++++-- .../gwt/ui/adminconsole/EventEditDialog.java | 2 ++ .../adminconsole/ExternalLinksComposite.java | 22 +++++-------------- .../sailing/gwt/ui/client/StringMessages.java | 2 +- .../gwt/ui/client/StringMessages.properties | 2 +- 6 files changed, 17 insertions(+), 20 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java index e876fea9cd1..246c5882ff5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java @@ -40,6 +40,8 @@ public class EventCreateDialog extends EventDialog { isPublicCheckBox = createCheckbox(""); isPublicCheckBox.setValue(false); isPublicCheckBox.ensureDebugId("IsPublicCheckBox"); + baseURLEntryField = createTextBox(null); + baseURLEntryField.setVisibleLength(50); imagesListComposite.fillImages(Collections.emptyList()); videosListComposite.fillVideos(Collections.emptyList()); // add default course area diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index 95e3d4e34a4..ad7029a220e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java @@ -46,6 +46,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap protected BetterDateTimeBox endDateBox; protected CheckBox isPublicCheckBox; protected UUID id; + protected TextBox baseURLEntryField; protected CourseAreaListInlineEditorComposite courseAreaNameList; protected StringConstantsListEditorComposite leaderboardGroupList; protected Map availableLeaderboardGroupsByName; @@ -174,7 +175,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap result.setName(nameEntryField.getText()); result.setDescription(descriptionEntryField.getText()); result.setOfficialWebsiteURL(externalLinksComposite.getOfficialWebsiteURLValue()); - result.setBaseURL(externalLinksComposite.getBaseURLValue()); + result.setBaseURL(baseURLEntryField.getText().trim().isEmpty() ? null : baseURLEntryField.getText().trim()); result.setSailorsInfoWebsiteURLs(externalLinksComposite.getSailorsInfoWebsiteURLs()); result.startDate = startDateBox.getValue(); result.endDate = endDateBox.getValue(); @@ -199,7 +200,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap if (additionalWidget != null) { panel.add(additionalWidget); } - Grid formGrid = new Grid(7, 2); + Grid formGrid = new Grid(8, 2); int rowIndex = 0; formGrid.setWidget(rowIndex, 0, new Label(stringMessages.name() + ":")); formGrid.setWidget(rowIndex++, 1, nameEntryField); @@ -215,6 +216,8 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap formGrid.setWidget(rowIndex++, 1, endDateBox); formGrid.setWidget(rowIndex, 0, new Label(stringMessages.isPublic() + ":")); formGrid.setWidget(rowIndex++, 1, isPublicCheckBox); + formGrid.setWidget(rowIndex, 0, new Label(stringMessages.eventBaseURL() + ":")); + formGrid.setWidget(rowIndex++, 1, baseURLEntryField); TabLayoutPanel tabPanel = new TabLayoutPanel(30, Unit.PX); tabPanel.ensureDebugId("EventDialogTabs"); tabPanel.setHeight("525px"); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java index 036440cef6b..e85f8f25bf0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java @@ -27,6 +27,8 @@ public class EventEditDialog extends EventDialog { endDateBox.setFormat("dd/mm/yyyy hh:ii"); isPublicCheckBox = createCheckbox(""); isPublicCheckBox.setValue(event.isPublic); + baseURLEntryField = createTextBox(event.getBaseURL()); + baseURLEntryField.setVisibleLength(50); id = event.id; courseAreaNameList.setValue(new ArrayList<>(event.venue.getCourseAreas())); List leaderboardGroupNames = new ArrayList<>(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExternalLinksComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExternalLinksComposite.java index a5b770a3994..0b6e3f4dc40 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExternalLinksComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExternalLinksComposite.java @@ -19,7 +19,6 @@ public class ExternalLinksComposite extends Composite { private Map sailorsInfoWebsiteURLEntryFields = new HashMap<>(); private TextBox officialWebsiteURLEntryField; - private TextBox baseURLEntryField; private StringMessages stringMessages; @@ -28,22 +27,19 @@ public class ExternalLinksComposite extends Composite { officialWebsiteURLEntryField = new TextBox(); officialWebsiteURLEntryField.setVisibleLength(50); - baseURLEntryField = new TextBox(); - baseURLEntryField.setVisibleLength(50); sailorsInfoWebsiteURLEntryFields = createTextBoxesForLocalesAndDefault(Collections. emptyMap()); int rowIndex = 0; - Grid formGrid = new Grid(GWTLocaleUtil.getLanguageCountWithDefault() + 3, 2); + Grid formGrid = new Grid(GWTLocaleUtil.getLanguageCountWithDefault() + 2, 2); formGrid.setWidget(rowIndex, 0, new Label(stringMessages.eventOfficialWebsiteURL() + ":")); formGrid.setWidget(rowIndex++, 1, officialWebsiteURLEntryField); - formGrid.setWidget(rowIndex, 0, new Label(stringMessages.eventBaseURL() + ":")); - formGrid.setWidget(rowIndex++, 1, baseURLEntryField); Map languageByLocaleMap = getLanguageByLocaleMap(); for (Map.Entry sailorsInfoWebsiteUrlEntry : sailorsInfoWebsiteURLEntryFields.entrySet()) { String locale = sailorsInfoWebsiteUrlEntry.getKey(); - String suffix = " [" + (locale == null ? stringMessages.defaultLocale() + "*" : locale) + "]"; - formGrid.setWidget(rowIndex, 0, new Label( - stringMessages.eventLocaleSailorsInfoWebsiteURL(languageByLocaleMap.get(locale)) + suffix + ":")); + String suffix = " [" + (locale == null ? stringMessages.allLanguages() + "*" : locale) + "]"; + String text = locale == null ? stringMessages.eventSailorsInfoWebsiteURL() + : stringMessages.eventLocaleSailorsInfoWebsiteURL(languageByLocaleMap.get(locale)); + formGrid.setWidget(rowIndex, 0, new Label(text + suffix + ":")); formGrid.setWidget(rowIndex, 1, sailorsInfoWebsiteUrlEntry.getValue()); rowIndex++; } @@ -60,11 +56,6 @@ public class ExternalLinksComposite extends Composite { return value.isEmpty() ? null : value; } - public String getBaseURLValue() { - String value = baseURLEntryField.getText().trim(); - return value.isEmpty() ? null : value; - } - public Map getSailorsInfoWebsiteURLs() { Map sailorsInfoWebsiteURLsMap = new HashMap<>(); for (Map.Entry sailorsInfoWebsiteUrlEntry : sailorsInfoWebsiteURLEntryFields.entrySet()) { @@ -82,7 +73,6 @@ public class ExternalLinksComposite extends Composite { sailorsInfoWebsiteURLEntryFields.get(localeName).setValue(initialValues.get(localeName)); } officialWebsiteURLEntryField.setValue(event.getOfficialWebsiteURL()); - baseURLEntryField.setValue(event.getBaseURL()); } private Map createTextBoxesForLocalesAndDefault(Map initialValues) { @@ -98,7 +88,7 @@ public class ExternalLinksComposite extends Composite { private Map getLanguageByLocaleMap() { Map languageByLocaleMap = new HashMap<>(); - languageByLocaleMap.put(null, stringMessages.unspecified()); + languageByLocaleMap.put(null, stringMessages.allLanguages()); languageByLocaleMap.put("en", stringMessages.english()); languageByLocaleMap.put("de", stringMessages.german()); languageByLocaleMap.put("ja", stringMessages.japanese()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 20cca3cab05..77ca6944a68 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -1637,7 +1637,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String notificationAboutUpcomingRaces(); String eventLocaleSailorsInfoWebsiteURL(String language); String externalLinks(); - String unspecified(); + String allLanguages(); String english(); String german(); String russian(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index c23a0a7eaa8..87c1204ee0b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -1610,7 +1610,7 @@ winningLanes=Winning lanes maximumNumberOfDiscards=Maximum number of discards externalLinks=External links eventLocaleSailorsInfoWebsiteURL=URL for {0} language -unspecified=unspecified +allLanguages=All languages english=english german=german russian=russian From ec3f526428951bc67c0ffb2f83ec4c465f702880 Mon Sep 17 00:00:00 2001 From: Alexander Tatarinovich Date: Wed, 12 Oct 2016 17:42:44 +0300 Subject: [PATCH 05/31] Bug 3866 - Enable User Management/SAPHeader in Leaderboard.html Change-Id: I1ceae5e94eb1bcc45f09a30258763f59ba5cb1b8 --- .../ui/leaderboard/LeaderboardEntryPoint.java | 26 ++++--------------- .../sap/sailing/gwt/ui/Leaderboard.gwt.xml | 1 + 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardEntryPoint.java index 44e0e66d4dd..107d1277112 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardEntryPoint.java @@ -21,9 +21,9 @@ import com.sap.sailing.domain.common.LeaderboardType; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.RegattaNameAndRaceName; import com.sap.sailing.domain.common.dto.AbstractLeaderboardDTO; +import com.sap.sailing.gwt.common.authentication.FixedSailingAuthentication; +import com.sap.sailing.gwt.common.authentication.SAPSailingHeaderWithAuthentication; import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint; -import com.sap.sailing.gwt.ui.client.GlobalNavigationPanel; -import com.sap.sailing.gwt.ui.client.LogoAndTitlePanel; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.leaderboard.LeaderboardSettings.RaceColumnSelectionStrategies; import com.sap.sailing.gwt.ui.shared.EventDTO; @@ -45,7 +45,6 @@ public class LeaderboardEntryPoint extends AbstractSailingEntryPoint { private String leaderboardName; private String leaderboardGroupName; private LeaderboardType leaderboardType; - private GlobalNavigationPanel globalNavigationPanel; private EventDTO event; @Override @@ -121,30 +120,15 @@ public class LeaderboardEntryPoint extends AbstractSailingEntryPoint { private void createUI(boolean showRaceDetails, boolean embedded, boolean hideToolbar, EventDTO event) { DockLayoutPanel mainPanel = new DockLayoutPanel(Unit.PX); RootLayoutPanel.get().add(mainPanel); - LogoAndTitlePanel logoAndTitlePanel = null; if (!embedded) { // Hack to shorten the leaderboardName in case of overall leaderboards String leaderboardDisplayName = Window.Location.getParameter("displayName"); if (leaderboardDisplayName == null || leaderboardDisplayName.isEmpty()) { leaderboardDisplayName = leaderboardName; } - globalNavigationPanel = new GlobalNavigationPanel(getStringMessages(), true, null, leaderboardGroupName, event, null); - logoAndTitlePanel = new LogoAndTitlePanel(leaderboardGroupName, leaderboardDisplayName, getStringMessages(), this, getUserService()) { - @Override - public void onResize() { - super.onResize(); - if (isSmallWidth()) { - remove(globalNavigationPanel); - } else { - add(globalNavigationPanel); - } - } - }; - logoAndTitlePanel.addStyleName("LogoAndTitlePanel"); - if (!isSmallWidth()) { - logoAndTitlePanel.add(globalNavigationPanel); - } - mainPanel.addNorth(logoAndTitlePanel, 68); + SAPSailingHeaderWithAuthentication header = new SAPSailingHeaderWithAuthentication(leaderboardDisplayName); + new FixedSailingAuthentication(getUserService(), header.getAuthenticationMenuView()); + mainPanel.addNorth(header, 75); } ScrollPanel contentScrollPanel = new ScrollPanel(); long delayBetweenAutoAdvancesInMilliseconds = DEFAULT_REFRESH_INTERVAL_MILLIS; diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Leaderboard.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Leaderboard.gwt.xml index dc3971ece1c..392a679e575 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Leaderboard.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/Leaderboard.gwt.xml @@ -37,4 +37,5 @@ + From b9a96f0d98431fd260f75742396ba93f55f857b0 Mon Sep 17 00:00:00 2001 From: Alexander Tatarinovich Date: Tue, 18 Oct 2016 11:39:14 +0300 Subject: [PATCH 06/31] Bug 3233: When file upload takes too long, URL is not filled. Change-Id: Id79405a33e3b79b8f4ed683ec79e279babe985b5 --- .../server/gateway/impl/FileUploadServlet.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/FileUploadServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/FileUploadServlet.java index 72cd10d3c1f..f04188806b5 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/FileUploadServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/FileUploadServlet.java @@ -9,8 +9,6 @@ import java.util.logging.Logger; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import org.apache.commons.fileupload.FileItem; @@ -40,7 +38,7 @@ public class FileUploadServlet extends AbstractFileUploadServlet { /** * The maximum size of an image uploaded by a user as a team image, in megabytes (1024*1024 bytes) */ - private static final int MAX_SIZE_IN_MB = 5; + private static final int MAX_SIZE_IN_MB = 500; @Override protected void process(List fileItems, HttpServletRequest req, HttpServletResponse resp) throws UnsupportedEncodingException, IOException { @@ -61,13 +59,15 @@ public class FileUploadServlet extends AbstractFileUploadServlet { } try { if (fileItem.getSize() > 1024 * 1024 * MAX_SIZE_IN_MB) { - throw new WebApplicationException(Response.status(Status.BAD_REQUEST) - .entity("Image is larger than " + MAX_SIZE_IN_MB + "MB").build()); + final String errorMessage = "Image is larger than " + MAX_SIZE_IN_MB + "MB"; + result.put("status", Status.INTERNAL_SERVER_ERROR.name()); + result.put("message", errorMessage); + } else { + final URI fileUri = getService().getFileStorageManagementService().getActiveFileStorageService() + .storeFile(fileItem.getInputStream(), fileExtension, fileItem.getSize()); + result.put(JSON_FILE_NAME, fileItem.getName()); + result.put(JSON_FILE_URI, fileUri.toString()); } - final URI fileUri = getService().getFileStorageManagementService().getActiveFileStorageService() - .storeFile(fileItem.getInputStream(), fileExtension, fileItem.getSize()); - result.put(JSON_FILE_NAME, fileItem.getName()); - result.put(JSON_FILE_URI, fileUri.toString()); } catch (IOException | OperationFailedException | InvalidPropertiesException | NoCorrespondingServiceRegisteredException e) { final String errorMessage = "Could not store file"+ (e.getMessage()==null?"":(": " + e.getMessage())); logger.log(Level.WARNING, "Could not store file", e); From 9ada8943737fdd8c85c4ebef878e1588ca5ea7c5 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Tue, 18 Oct 2016 16:22:49 +0200 Subject: [PATCH 07/31] Implemented KPI for the rank after the half of the first leg for races of competitors --- .../Sailing_StringMessages.properties | 3 ++- .../Sailing_StringMessages_de.properties | 3 ++- .../com/sap/sailing/datamining/Activator.java | 8 +++----- .../data/HasRaceOfCompetitorContext.java | 5 ++++- .../datamining/impl/data/GPSFixWithContext.java | 2 +- .../impl/data/RaceOfCompetitorWithContext.java | 17 ++++++++++++++++- 6 files changed, 28 insertions(+), 10 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 7674dbcea9a..02c56d2193d 100644 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties @@ -76,4 +76,5 @@ PassingSide=Passing Side TackAtStart=Tack at Start SpeedTenSecondsAfterStart=Speed 10s After Start RankThirtySecondsAfterStart=Rank 30s After Start -StartAdvantage=Start Advantage \ No newline at end of file +StartAdvantage=Start Advantage +RankAfterHalfOfTheFirstLeg=Rank after the half of the first leg \ No newline at end of file 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 2bf8f9b7dcf..e0a7d0556c3 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 @@ -76,4 +76,5 @@ PassingSide=Passierende Seite TackAtStart=Startbug SpeedTenSecondsAfterStart=Geschwindigkeit 10s nach dem Startzeitpunkt RankThirtySecondsAfterStart=Absolute Platzierung 30s nach dem Startzeitpunkt -StartAdvantage=Startvorteil \ No newline at end of file +StartAdvantage=Startvorteil +RankAfterHalfOfTheFirstLeg=Platzierung nach der Hälfte des ersten Schenkels \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/Activator.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/Activator.java index 2e0f2f683e2..183cba04870 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/Activator.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/Activator.java @@ -23,11 +23,9 @@ import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceMa import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceMedianAggregationProcessor; import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceMinAggregationProcessor; import com.sap.sailing.datamining.impl.components.aggregators.ParallelDistanceSumAggregationProcessor; -import com.sap.sailing.domain.common.Speed; import com.sap.sse.datamining.DataSourceProvider; import com.sap.sse.datamining.components.AggregationProcessorDefinition; import com.sap.sse.datamining.components.DataRetrieverChainDefinition; -import com.sap.sse.datamining.data.ClusterGroup; import com.sap.sse.datamining.impl.AbstractDataMiningActivatorWithPredefinedQueries; import com.sap.sse.datamining.shared.dto.StatisticQueryDefinitionDTO; import com.sap.sse.datamining.shared.impl.PredefinedQueryIdentifier; @@ -126,9 +124,9 @@ public class Activator extends AbstractDataMiningActivatorWithPredefinedQueries dataSourceProviders = new HashSet<>(); dataSourceProviders.add(new RacingEventServiceProvider(context)); } - - public static ClusterGroup getWindStrengthInBeaufortClusterGroup() { - return clusterGroups.getWindStrengthInBeaufortCluster(); + + public static SailingClusterGroups getClusterGroups() { + return clusterGroups; } public static Activator getDefault() { 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 d2441fd0e7b..1103331021a 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 @@ -42,7 +42,10 @@ public interface HasRaceOfCompetitorContext { public Speed getSpeedTenSecondsAfterStart(); @Statistic(messageKey="RankThirtySecondsAfterStart", resultDecimals=2, ordinal=5) - public Double getAbsoluteRankThirtySecondsAfterStart(); + public Double getRankThirtySecondsAfterStart(); + + @Statistic(messageKey="RankAfterHalfOfTheFirstLeg", resultDecimals=2, ordinal=6) + public Double getRankAfterHalfOfTheFirstLeg(); @Statistic(messageKey="RankAtFirstMark", resultDecimals=2, ordinal=6) public Double getRankAtFirstMark(); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/GPSFixWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/GPSFixWithContext.java index d555d03b652..65830923d3e 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/GPSFixWithContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/GPSFixWithContext.java @@ -36,7 +36,7 @@ public class GPSFixWithContext implements HasGPSFixContext { @Override public ClusterDTO getWindStrengthAsBeaufortCluster(Locale locale, ResourceBundleStringMessages stringMessages) { Wind wind = getWind(); - Cluster cluster = Activator.getWindStrengthInBeaufortClusterGroup().getClusterFor(wind); + Cluster cluster = Activator.getClusterGroups().getWindStrengthInBeaufortClusterGroup().getClusterFor(wind); return new ClusterDTO(cluster.asLocalizedString(locale, stringMessages)); } 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 8ce5e4bf821..89200db8ad1 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 @@ -91,7 +91,7 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext { } @Override - public Double getAbsoluteRankThirtySecondsAfterStart() { + public Double getRankThirtySecondsAfterStart() { TimePoint startOfRace = getTrackedRace().getStartOfRace(); if (startOfRace == null) { return null; @@ -101,6 +101,21 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext { return rank == 0 ? null : Double.valueOf(rank); } + @Override + public Double getRankAfterHalfOfTheFirstLeg() { + Course course = getTrackedRace().getRace().getCourse(); + TrackedLegOfCompetitor trackedLeg = getTrackedRace().getTrackedLeg(getCompetitor(), course.getFirstLeg()); + TimePoint startTime = trackedLeg.getStartTime(); + TimePoint finishTime = trackedLeg.getFinishTime(); + if (startTime == null || finishTime == null) { + return null; + } + + long halfOffset = (finishTime.asMillis() - startTime.asMillis()) / 2; + int rank = getTrackedRace().getRank(getCompetitor(), startTime.plus(halfOffset)); + return rank == 0 ? null : Double.valueOf(rank); + } + @Override public Double getRankAtFirstMark() { Course course = getTrackedRace().getRace().getCourse(); From f73b2f138a7b0d3c288660bf3416c2b89eb5d3cd Mon Sep 17 00:00:00 2001 From: Kai Boernert Date: Tue, 18 Oct 2016 17:37:17 +0200 Subject: [PATCH 08/31] npe fix for bug3950, based on missing livecyclesetting objects --- .../client/place/player/PlayerActivity.java | 33 +++++++++++++++++-- .../client/place/player/PlayerPlace.java | 2 ++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/place/player/PlayerActivity.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/place/player/PlayerActivity.java index d2e3019ccaa..2d8831be66f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/place/player/PlayerActivity.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/place/player/PlayerActivity.java @@ -7,8 +7,16 @@ import com.google.gwt.event.shared.EventBus; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.AcceptsOneWidget; +import com.sap.sailing.gwt.autoplay.client.shared.leaderboard.LeaderboardWithHeaderPerspectiveLifecycle; +import com.sap.sailing.gwt.autoplay.client.shared.leaderboard.LeaderboardWithHeaderPerspectiveSettings; +import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sailing.gwt.ui.raceboard.RaceBoardPerspectiveLifecycle; +import com.sap.sailing.gwt.ui.raceboard.RaceBoardPerspectiveSettings; import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; +import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO; import com.sap.sse.gwt.client.mvp.ErrorView; +import com.sap.sse.gwt.client.shared.perspective.PerspectiveLifecycleWithAllSettings; import com.sap.sse.gwt.client.useragent.UserAgentDetails; import com.sap.sse.gwt.shared.GwtHttpRequestUtils; @@ -26,6 +34,17 @@ public class PlayerActivity extends AbstractActivity { this.autoPlayController = null; } + private StrippedLeaderboardDTO getSelectedLeaderboard(EventDTO event,String leaderBoardName) { + for (LeaderboardGroupDTO leaderboardGroup : event.getLeaderboardGroups()) { + for (StrippedLeaderboardDTO leaderboard : leaderboardGroup.getLeaderboards()) { + if (leaderboard.name.equals(leaderBoardName)) { + return leaderboard; + } + } + } + return null; + } + @Override public void start(final AcceptsOneWidget panel, EventBus eventBus) { final boolean showRaceDetails = GwtHttpRequestUtils.getBooleanParameter(PARAM_SHOW_RACE_DETAILS, false); @@ -36,6 +55,16 @@ public class PlayerActivity extends AbstractActivity { clientFactory.getSailingService().getEventById(eventUUID, true, new AsyncCallback() { @Override public void onSuccess(final EventDTO event) { + + //This place fixes a specific null pointer bug3950, once the settings are redone, this should be removed, and instead be done via playerplace (see comment there) + StrippedLeaderboardDTO leaderBoardDTO = getSelectedLeaderboard(event,playerPlace.getConfiguration().getLeaderboardName()); + LeaderboardWithHeaderPerspectiveLifecycle leaderboardPerspectiveLifecycle = new LeaderboardWithHeaderPerspectiveLifecycle(leaderBoardDTO, StringMessages.INSTANCE); + PerspectiveLifecycleWithAllSettings leaderboardPerspectiveLifecyclesAndSettings = new PerspectiveLifecycleWithAllSettings<>(leaderboardPerspectiveLifecycle, leaderboardPerspectiveLifecycle.createDefaultSettings()); + RaceBoardPerspectiveLifecycle raceboardPerspectiveLifecycle = new RaceBoardPerspectiveLifecycle(leaderBoardDTO, StringMessages.INSTANCE); + PerspectiveLifecycleWithAllSettings raceboardPerspectiveLifecyclesAndSettings = new PerspectiveLifecycleWithAllSettings<>(raceboardPerspectiveLifecycle, raceboardPerspectiveLifecycle.createDefaultSettings()); + + + UserAgentDetails userAgent = new UserAgentDetails(Window.Navigator.getUserAgent()); PlayerView view = clientFactory.createPlayerView(); @@ -44,8 +73,8 @@ public class PlayerActivity extends AbstractActivity { autoPlayController = new AutoPlayController(clientFactory.getSailingService(), clientFactory .getMediaService(), clientFactory.getUserService(), clientFactory.getErrorReporter(), playerPlace.getConfiguration(), userAgent, delayToLiveMillis, showRaceDetails, view, - playerPlace.getLeaderboardPerspectiveLifecycleWithAllSettings(), - playerPlace.getRaceboardPerspectiveLifecycleWithAllSettings()); + leaderboardPerspectiveLifecyclesAndSettings, + raceboardPerspectiveLifecyclesAndSettings); autoPlayController.updatePlayMode(AutoPlayModes.Leaderboard); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/place/player/PlayerPlace.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/place/player/PlayerPlace.java index a5736f46d65..e0c45b26985 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/place/player/PlayerPlace.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/place/player/PlayerPlace.java @@ -23,6 +23,8 @@ public class PlayerPlace extends AbstractBasePlace { Integer timeToSwitchBeforeRaceStartInSeconds = Integer.valueOf(getParameter(AutoPlayerConfiguration.PARAM_TIME_TO_SWITCH_BEFORE_RACE_START)); this.playerConfiguration = new AutoPlayerConfiguration(eventUuidAsString, leaderboardName, fullscreen, timeToSwitchBeforeRaceStartInSeconds); + + //these are currently regenerated in the PlayerActivity, based on the historydata. Once the settings are properly stored, this should be replaced. this.leaderboardPerspectiveLifecycleWithAllSettings = null; this.raceboardPerspectiveLifecycleWithAllSettings = null; } From 69a4ef0abfda7dd184045711c6609ba661412efc Mon Sep 17 00:00:00 2001 From: Alexander Tatarinovich Date: Wed, 19 Oct 2016 11:29:49 +0300 Subject: [PATCH 09/31] bug3866: fix size toolbar buttons Change-Id: I3faa6d2180acd018c2397e0c37abe513ed3a14d2 --- .../java/com/sap/sailing/gwt/ui/leaderboard/ViewerToolbar.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ViewerToolbar.css b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ViewerToolbar.css index d55a8630c74..769bf019f09 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ViewerToolbar.css +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ViewerToolbar.css @@ -76,7 +76,7 @@ font-size: 14px; margin: 0 0 0 0; padding: 2px 7px 2px 3px; - height: 18px; + height: 22px; display: inline-block; text-decoration: none; -moz-border-radius: 5px 0 0 5px; From e6c29f5a6e2b6104c54f3fe0652c5a6c71a0c33e Mon Sep 17 00:00:00 2001 From: fmittag Date: Wed, 19 Oct 2016 13:37:51 +0200 Subject: [PATCH 10/31] Improved layout and labels of 'sailors info url' fields --- .../adminconsole/ExternalLinksComposite.java | 35 +++++++------------ .../sailing/gwt/ui/client/StringMessages.java | 9 ++--- .../gwt/ui/client/StringMessages.properties | 9 ++--- .../ui/client/StringMessages_de.properties | 9 ++--- 4 files changed, 18 insertions(+), 44 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExternalLinksComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExternalLinksComposite.java index 0b6e3f4dc40..9cc9e1fa51d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExternalLinksComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExternalLinksComposite.java @@ -5,9 +5,10 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.i18n.client.LocaleInfo; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.Grid; - import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; @@ -20,32 +21,31 @@ public class ExternalLinksComposite extends Composite { private Map sailorsInfoWebsiteURLEntryFields = new HashMap<>(); private TextBox officialWebsiteURLEntryField; - private StringMessages stringMessages; - public ExternalLinksComposite(StringMessages stringMessages) { - this.stringMessages = stringMessages; + VerticalPanel panel = new VerticalPanel(); + panel.setWidth("100%"); officialWebsiteURLEntryField = new TextBox(); officialWebsiteURLEntryField.setVisibleLength(50); sailorsInfoWebsiteURLEntryFields = createTextBoxesForLocalesAndDefault(Collections. emptyMap()); int rowIndex = 0; - Grid formGrid = new Grid(GWTLocaleUtil.getLanguageCountWithDefault() + 2, 2); + Grid formGrid = new Grid(GWTLocaleUtil.getLanguageCountWithDefault() + 3, 2); formGrid.setWidget(rowIndex, 0, new Label(stringMessages.eventOfficialWebsiteURL() + ":")); formGrid.setWidget(rowIndex++, 1, officialWebsiteURLEntryField); - Map languageByLocaleMap = getLanguageByLocaleMap(); + formGrid.setWidget(rowIndex++, 0, new Label(stringMessages.eventSailorsInfoWebsiteURL())); for (Map.Entry sailorsInfoWebsiteUrlEntry : sailorsInfoWebsiteURLEntryFields.entrySet()) { String locale = sailorsInfoWebsiteUrlEntry.getKey(); - String suffix = " [" + (locale == null ? stringMessages.allLanguages() + "*" : locale) + "]"; - String text = locale == null ? stringMessages.eventSailorsInfoWebsiteURL() - : stringMessages.eventLocaleSailorsInfoWebsiteURL(languageByLocaleMap.get(locale)); - formGrid.setWidget(rowIndex, 0, new Label(text + suffix + ":")); + String suffix = locale == null ? "*" : "[" + locale + "]"; + String text = locale == null ? stringMessages.urlForAllLanguages() + : stringMessages.urlForLanguage(LocaleInfo.getLocaleNativeDisplayName(locale)); + Label urlLabel = new Label(text + " " + suffix + ":"); + urlLabel.getElement().getStyle().setMarginLeft(10, Unit.PX); + formGrid.setWidget(rowIndex, 0, urlLabel); formGrid.setWidget(rowIndex, 1, sailorsInfoWebsiteUrlEntry.getValue()); rowIndex++; } - VerticalPanel panel = new VerticalPanel(); - panel.setWidth("100%"); panel.add(formGrid); panel.add(new Label("[*] " + stringMessages.defaultSailorsInfoLinkInfoText())); initWidget(panel); @@ -85,15 +85,4 @@ public class ExternalLinksComposite extends Composite { } return result; } - - private Map getLanguageByLocaleMap() { - Map languageByLocaleMap = new HashMap<>(); - languageByLocaleMap.put(null, stringMessages.allLanguages()); - languageByLocaleMap.put("en", stringMessages.english()); - languageByLocaleMap.put("de", stringMessages.german()); - languageByLocaleMap.put("ja", stringMessages.japanese()); - languageByLocaleMap.put("ru", stringMessages.russian()); - languageByLocaleMap.put("zh", stringMessages.сhinese()); - return languageByLocaleMap; - } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index eb2fc95cd44..5ce2465ff2d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -1736,12 +1736,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String lastFix(); String filterDeviceMappings(); String raceStartAnalysis(); - String eventLocaleSailorsInfoWebsiteURL(String language); + String urlForLanguage(String language); + String urlForAllLanguages(); String externalLinks(); - String allLanguages(); - String english(); - String german(); - String russian(); - String japanese(); - String сhinese(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 3a9cecc2e18..f010cb4db14 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -1615,13 +1615,8 @@ startAnalysis=Start analysis winningLanes=Winning lanes maximumNumberOfDiscards=Maximum number of discards externalLinks=External links -eventLocaleSailorsInfoWebsiteURL=URL for ''{0}'' -allLanguages=All languages -english=english -german=german -russian=russian -japanese=japanese -сhinese=сhinese +urlForAllLanguages=URL for all languages +urlForLanguage=URL for language ''{0}'' notificationRegattaConfigurationUpdatedUsingByMarks=Active regatta configuration was set, using the "By Marks" course designer. warningOverrideRegattaConfigurationCourseDesignerToByMarks=Active regatta configuration already exists, but with the wrong course designer setting.\nWould you like to override course designer setting to "By Marks"? allRacesHaveBeenDenoted=All races have been denoted for racelog tracking. diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index c167fdb4ca5..2bffe46202b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -1601,13 +1601,8 @@ startAnalysis=Start-Analyse winningLanes=Sieger-Kurse maximumNumberOfDiscards=Maximale Anzahl von Streichern externalLinks=Externe Links -eventLocaleSailorsInfoWebsiteURL=URL für ''{0}'' -allLanguages=Alle Sprachen -english=englisch -german=deutsch -russian=russisch -japanese=japanisch -сhinese=chinesisch +urlForAllLanguages=URL für alle Sprachen +urlForLanguage=URL für die Sprache ''{0}'' notificationRegattaConfigurationUpdatedUsingByMarks=Aktive Regattakonfiguration wurde gesetzt, "By Marks" Kursdesigner ist ausgewählt. warningOverrideRegattaConfigurationCourseDesignerToByMarks=Aktive Regattakonfiguration existiert bereits, verwendet aber den falschenKursdesigner.\nKursdesigner auf "By Marks" umstellen? allRacesHaveBeenDenoted=Alle Rennen sind für Smartphone Tracking gekennzeichnet worden. From bd15762f6bd326fafbd1ba53f43e52cdf0e64be1 Mon Sep 17 00:00:00 2001 From: fmittag Date: Wed, 19 Oct 2016 13:39:24 +0200 Subject: [PATCH 11/31] Reduced overall height of event dialog --- .../java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index ad7029a220e..828edc88239 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java @@ -220,7 +220,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap formGrid.setWidget(rowIndex++, 1, baseURLEntryField); TabLayoutPanel tabPanel = new TabLayoutPanel(30, Unit.PX); tabPanel.ensureDebugId("EventDialogTabs"); - tabPanel.setHeight("525px"); + tabPanel.setHeight("400px"); panel.add(tabPanel); final ScrollPanel eventTab = new ScrollPanel(formGrid); eventTab.ensureDebugId("EventTab"); From ee334fcada9735b6cc9cc0351443848c2dd68da5 Mon Sep 17 00:00:00 2001 From: fmittag Date: Wed, 19 Oct 2016 14:14:34 +0200 Subject: [PATCH 12/31] Added message keys to other languages --- .../sap/sailing/gwt/ui/client/StringMessages_ja.properties | 3 +++ .../sap/sailing/gwt/ui/client/StringMessages_ru.properties | 3 +++ .../sap/sailing/gwt/ui/client/StringMessages_zh.properties | 4 +++- .../sap/sailing/gwt/ui/client/StringMessages_zh_CN.properties | 3 +++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties index 8ec136ff41b..3865f5b0233 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties @@ -1612,6 +1612,9 @@ raceAnalysis=レース分析 startAnalysis=スタート分析 winningLanes=勝利レーン maximumNumberOfDiscards=カットレースの最大数 +externalLinks=External links +urlForAllLanguages=URL for all languages +urlForLanguage=URL for language ''{0}'' notificationRegattaConfigurationUpdatedUsingByMarks="マーク別" コースデザイナーを使用して、有効なレガッタ設定が行われました。 warningOverrideRegattaConfigurationCourseDesignerToByMarks=有効なレガッタ設定がすでに登録されていますが、コースデザイナーの設定が適切でありません。\n"マーク別" へのコースデザイナー設定を上書きしますか。 allRacesHaveBeenDenoted=すべてのレースがレースログ追跡に表示されています。 diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties index 94466bff2c6..4beeff7e33f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties @@ -1612,6 +1612,9 @@ raceAnalysis=Анализ гонки startAnalysis=Начать анализ winningLanes=Выигрышные маршруты maximumNumberOfDiscards=Максимальное число исключений +externalLinks=External links +urlForAllLanguages=URL for all languages +urlForLanguage=URL for language ''{0}'' notificationRegattaConfigurationUpdatedUsingByMarks=Активная конфигурация регаты была настроена с использованием дизайнера курса "По отметкам". warningOverrideRegattaConfigurationCourseDesignerToByMarks=Активная конфигурация регаты уже существует, но с неверно выбранным дизайнером курса.\nПереопределить выбор дизайнера курса на "По отметкам"? allRacesHaveBeenDenoted=Отслеживание журнала всех гонок отменено. diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties index 1e00ca7d20d..e648ab55be3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties @@ -1610,7 +1610,9 @@ raceAnalysis=比赛轮次分析 startAnalysis=起航分析 winningLanes=获胜的船道 maximumNumberOfDiscards=最大放弃次数 - +externalLinks=External links +urlForAllLanguages=URL for all languages +urlForLanguage=URL for language ''{0}'' chartSelectionHint=提示:您还可以使用积分榜(在 LEADERBOARD 选项卡中)选择在记录中显示的参赛队。 chooseALanguage=选择一种语言 solutions=解决方案 diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh_CN.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh_CN.properties index a74bb40da7e..adb4f208fb6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh_CN.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh_CN.properties @@ -1612,6 +1612,9 @@ raceAnalysis=比赛轮次分析 startAnalysis=起航分析 winningLanes=获胜的船道 maximumNumberOfDiscards=最大放弃次数 +externalLinks=External links +urlForAllLanguages=URL for all languages +urlForLanguage=URL for language ''{0}'' notificationRegattaConfigurationUpdatedUsingByMarks=已使用“按标志”场地设计器设置有效的比赛配置。 warningOverrideRegattaConfigurationCourseDesignerToByMarks=有效的比赛配置已存在,但是场地设计器设置错误。\n是否将场地设计器设置覆盖为“按标志”? allRacesHaveBeenDenoted=已为比赛轮次日志跟踪描述所有比赛轮次。 From 00cbfca35f17c00b347ff41758af4073a20c12ca Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 19 Oct 2016 15:24:03 +0200 Subject: [PATCH 13/31] added logging Change-Id: I4602f8c5f445d5c8e4098cf77955891572989ab3 --- .../com/sap/sailing/server/gateway/impl/FileUploadServlet.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/FileUploadServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/FileUploadServlet.java index f04188806b5..caf58194ef7 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/FileUploadServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/FileUploadServlet.java @@ -60,6 +60,7 @@ public class FileUploadServlet extends AbstractFileUploadServlet { try { if (fileItem.getSize() > 1024 * 1024 * MAX_SIZE_IN_MB) { final String errorMessage = "Image is larger than " + MAX_SIZE_IN_MB + "MB"; + logger.warning("Ignoring file storage request because file "+fileItem.getName()+" is larger than "+MAX_SIZE_IN_MB+"MB"); result.put("status", Status.INTERNAL_SERVER_ERROR.name()); result.put("message", errorMessage); } else { From 95d19183f261e71fa946e5080d4750c34758bbda Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 19 Oct 2016 18:49:30 +0200 Subject: [PATCH 14/31] URL-encode the access token when generating the URL displayed as a QR code for the device configurations in the admin console Change-Id: I2b861a8d42e8b75c5f46e35645e61b6993e0512a --- .../ui/adminconsole/DeviceConfigurationQRIdentifierDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationQRIdentifierDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationQRIdentifierDialog.java index 262c9887b4f..e2151dfc039 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationQRIdentifierDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationQRIdentifierDialog.java @@ -41,7 +41,7 @@ public class DeviceConfigurationQRIdentifierDialog extends DialogBox { Window.alert(stringMessages.notCapableOfGeneratingACodeForIdentifier()); } else if (!identifierBox.getValue().isEmpty() && !serverBox.getValue().isEmpty()) { String apkUrl = getServerUrlWithoutFinalSlash() + rcAppApkPath; - return DeviceConfigurationQRCodeUtils.composeQRContent(URL.encodeQueryString(identifierBox.getValue()), apkUrl, accessToken); + return DeviceConfigurationQRCodeUtils.composeQRContent(URL.encodeQueryString(identifierBox.getValue()), apkUrl, URL.encodeQueryString(accessToken)); } return null; } From 67a2e89088afbfcbda740c86b9f909ab98b205a0 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 19 Oct 2016 20:49:34 +0200 Subject: [PATCH 15/31] added release notes entry for URL encoding of access token parameter for QR code for Race Management app --- java/com.sap.sailing.www/release_notes_admin.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/java/com.sap.sailing.www/release_notes_admin.html b/java/com.sap.sailing.www/release_notes_admin.html index 2c2431489df..c66d961a3ac 100644 --- a/java/com.sap.sailing.www/release_notes_admin.html +++ b/java/com.sap.sailing.www/release_notes_admin.html @@ -29,6 +29,11 @@ can be used to determine the radius of the zone around the marks in terms of hull lengths. This sets the default for the race viewer (RaceBoard.html entry point) based on the hull length as known from the boat class. +
  • When producing the QR code for the Race Management App's device configurations, + the access token parameter was not properly URL-encoded. In case the access token + contains a '+' character it is incorrectly decoded by the app, letting the authentication + fail. This issue has now been fixed in the AdminConsole, and the access token parameter is + now properly URL-encoded.
  • September 2016

    From d0232fe71eb60d40b791bbbe25355f692506df40 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 20 Oct 2016 10:41:52 +0200 Subject: [PATCH 16/31] fixed a few German translations in the race management app Change-Id: I4d16f4aeeee2a0f7a9d77caedbb20e0e189eeb89 --- .../res/values-de/strings.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mobile/com.sap.sailing.racecommittee.app/res/values-de/strings.xml b/mobile/com.sap.sailing.racecommittee.app/res/values-de/strings.xml index 269424e2d43..08b55413332 100644 --- a/mobile/com.sap.sailing.racecommittee.app/res/values-de/strings.xml +++ b/mobile/com.sap.sailing.racecommittee.app/res/values-de/strings.xml @@ -460,20 +460,20 @@ N/A (vor %s) Vorheriger Kurs - Kurs Layout + Kurs-Layout ° Wegpunkt hinzufügen - Unpublished course design + Unveröffentlichtes Kurs-Layout Neu Zurücksetzen Soll die Liste komplett gelöscht werden? Soll die Liste zum letzten bekannten Stand zurückgesetzt werden? - Scan QR-Code + QR-Code scannen Manuelle Eingabe - Group Race - Select Race + Gruppenwettfahrt + Wettfahrt auswählen \'%1$s\' zur Ergebnisliste hinzugefügt an Position %2$s - Getting Started + Anmelden Position Server erfolgreich geändert auf %1$s. Strafe From dc04d0fe84358a0ab40f6bf377e0ddd0314568e6 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 20 Oct 2016 10:47:32 +0200 Subject: [PATCH 17/31] release notes entry for Race Management app Change-Id: I05e790a67bd056339b97b298d4dedf3cdbf6aa55 --- .../sailing/gwt/home/solutions/RaceCommitteeAppNotes.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/RaceCommitteeAppNotes.html b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/RaceCommitteeAppNotes.html index 4a7c5113a7f..b2cfb785b4e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/RaceCommitteeAppNotes.html +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/RaceCommitteeAppNotes.html @@ -4,6 +4,12 @@

    What's New - SAP Sailing Race Manager

    +
    October 2016
    + +
      +
    • Fixed missing German translations for some buttons and labels
    • +
    +
    September 2016
      From bf68e9dd2d315dc09dea68ea44215075f819ef9a Mon Sep 17 00:00:00 2001 From: Alexander Tatarinovich Date: Fri, 21 Oct 2016 09:29:03 +0300 Subject: [PATCH 18/31] Bug 2300 - Leaderboard buttons are not easily found Change-Id: Ic12afe9f36d4bbb5079a07eae8019afb5970d97f --- .../places/event/regatta/TabletAndDesktopRegattaEventView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/TabletAndDesktopRegattaEventView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/TabletAndDesktopRegattaEventView.java index b3c95caf26f..383fd6e7887 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/TabletAndDesktopRegattaEventView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/regatta/TabletAndDesktopRegattaEventView.java @@ -55,7 +55,7 @@ public class TabletAndDesktopRegattaEventView extends Composite implements Event if(currentPresenter.getEventDTO().getType() == EventType.SERIES_EVENT) { final PlaceNavigation currentEventSeriesNavigation = currentPresenter.getCurrentEventSeriesNavigation(); - Anchor seriesAnchor = new Anchor(currentPresenter.getEventDTO().getSeriesName()); + Anchor seriesAnchor = new Anchor(i18n.overallLeaderboardSelection()); seriesAnchor.setHref(currentEventSeriesNavigation.getTargetUrl()); seriesAnchor.addClickHandler(new ClickHandler() { @Override From 8a38e46f9564130d100efaed3f6f3e9ba0556e72 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 21 Oct 2016 12:35:51 +0200 Subject: [PATCH 19/31] in NaturalComparator use Long instead of Integer for number comparison Change-Id: If09c10c48072bf90aa1f9c05bc60477388666a99 --- .../src/com/sap/sse/common/util/NaturalComparator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/util/NaturalComparator.java b/java/com.sap.sse.common/src/com/sap/sse/common/util/NaturalComparator.java index d7c78e4e239..9dcfe60ac59 100755 --- a/java/com.sap.sse.common/src/com/sap/sse/common/util/NaturalComparator.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/util/NaturalComparator.java @@ -47,7 +47,7 @@ public class NaturalComparator implements Comparator { // Compare all-digit blocks as numbers - all-char blocks as strings if (Character.isDigit(aBlock.charAt(0)) && Character.isDigit(bBlock.charAt(0))) { - result = Integer.valueOf(aBlock).compareTo(Integer.valueOf(bBlock)); + result = Long.valueOf(aBlock).compareTo(Long.valueOf(bBlock)); } else { result = aBlock.compareTo(bBlock); } From e84394597f47dff1db90823b99c52535d3347538 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 21 Oct 2016 13:11:12 +0200 Subject: [PATCH 20/31] bug3964: computing avg SOG and ride height for entire race when race is finished Change-Id: I982325e724f891e88ed1a6297c18d8a71f38d1b8 --- .../common/dto/LeaderboardEntryDTO.java | 8 ++++ .../domain/test/mock/MockedTrackedRace.java | 8 ++-- ...ockedTrackedRaceWithStartTimeAndRanks.java | 5 +++ .../impl/AbstractSimpleLeaderboardImpl.java | 1 + .../sailing/domain/tracking/TrackedRace.java | 3 ++ .../impl/TrackedLegOfCompetitorImpl.java | 3 +- .../domain/tracking/impl/TrackedRaceImpl.java | 16 +++++++ .../gwt/ui/test/MockedTrackedRace.java | 5 +++ .../gwt/ui/leaderboard/LeaderboardPanel.java | 43 ++++++++++++++----- .../server/masterdata/DummyTrackedRace.java | 5 +++ 10 files changed, 82 insertions(+), 15 deletions(-) diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java index 1eab1c2ace2..390ec3246b1 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java @@ -78,6 +78,8 @@ public class LeaderboardEntryDTO implements Serializable { */ public Duration averageSamplingInterval; + public Double averageRideHeightInMeters; + /** * The time gap to the competitor leading the race; for one-design races this is the time the competitor is expected * to need to reach the leader's (windward) position (if in the same leg) or the difference between the time at @@ -174,6 +176,7 @@ public class LeaderboardEntryDTO implements Serializable { result = prime * result + ((speedOverGroundAtStartOfRaceInKnots == null) ? 0 : speedOverGroundAtStartOfRaceInKnots.hashCode()); result = prime * result + ((startTack == null) ? 0 : startTack.hashCode()); + result = prime * result + ((averageRideHeightInMeters == null) ? 0 : averageRideHeightInMeters.hashCode()); result = prime * result + ((averageSamplingInterval == null) ? 0 : averageSamplingInterval.hashCode()); result = prime * result + ((timeSinceLastPositionFixInSeconds == null) ? 0 : timeSinceLastPositionFixInSeconds.hashCode()); result = prime * result + ((netPoints == null) ? 0 : netPoints.hashCode()); @@ -282,6 +285,11 @@ public class LeaderboardEntryDTO implements Serializable { return false; if (startTack != other.startTack) return false; + if (averageRideHeightInMeters == null) { + if (other.averageRideHeightInMeters != null) + return false; + } else if (!averageRideHeightInMeters.equals(other.averageRideHeightInMeters)) + return false; if (averageSamplingInterval == null) { if (other.averageSamplingInterval != null) return false; diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java index e0119115587..d479e3bdacc 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java @@ -541,15 +541,12 @@ public class MockedTrackedRace implements DynamicTrackedRace { @Override public boolean isControlTrackingFromStartAndFinishTimes() { - // TODO Auto-generated method stub return false; } @Override public void setControlTrackingFromStartAndFinishTimes( boolean controlTrackingFromStartAndFinishTimes) { - // TODO Auto-generated method stub - } }; } @@ -1130,4 +1127,9 @@ public class MockedTrackedRace implements DynamicTrackedRace { public Iterable getAttachedRaceLogs() { return Collections.emptySet(); } + + @Override + public Double getAverageRideHeight(Competitor competitor, TimePoint timePoint) { + return null; + } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java index fefad810f2b..0d05f85c50f 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java @@ -681,4 +681,9 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace { public Iterable getAttachedRaceLogs() { return Collections.emptySet(); } + + @Override + public Double getAverageRideHeight(Competitor competitor, TimePoint timePoint) { + return null; + } } 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 083e5915d18..622447a5771 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 @@ -1437,6 +1437,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race } else { entryDTO.timeSinceLastPositionFixInSeconds = null; } + entryDTO.averageRideHeightInMeters = trackedRace.getAverageRideHeight(competitor, timePoint); } if (addLegDetails && trackedRace != null) { try { diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java index b9f36f9e1aa..9d40a0d9df5 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java @@ -47,6 +47,7 @@ import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.common.tracking.SensorFix; import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sailing.domain.polars.PolarDataService; +import com.sap.sailing.domain.racelog.tracking.GPSFixStore; import com.sap.sailing.domain.ranking.RankingMetric; import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sailing.domain.tracking.impl.NonCachingMarkPositionAtTimePointCache; @@ -685,6 +686,8 @@ public interface TrackedRace extends Serializable, IsManagedByCache track = getSensorTrack(competitor, BravoFixTrack.TRACK_NAME); + final Leg firstLeg; + final TrackedLegOfCompetitor firstTrackedLeg; + if (track != null && (firstLeg = getRace().getCourse().getFirstLeg()) != null && (firstTrackedLeg = getTrackedLeg(competitor, firstLeg)).hasStartedLeg(timePoint)) { + final TrackedLegOfCompetitor lastTrackedLeg = getTrackedLegFinishingAt(getRace().getCourse().getLastWaypoint()).getTrackedLeg(competitor); + TimePoint endTimePoint = lastTrackedLeg.hasFinishedLeg(timePoint) ? lastTrackedLeg.getFinishTime() : timePoint; + result = track.getAverageRideHeight(firstTrackedLeg.getStartTime(), endTimePoint); + } else { + result = null; + } + return result; + } + @Override public TrackedLegOfCompetitor getCurrentLeg(Competitor competitor, TimePoint timePoint) { // If the mark passing that starts a leg happened exactly at timePoint, the MarkPassingByTimeComparator won't consider diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java index b58478a3a82..1a3e75ffd46 100644 --- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java +++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java @@ -860,4 +860,9 @@ public class MockedTrackedRace implements DynamicTrackedRace { public Iterable getAttachedRaceLogs() { return Collections.emptySet(); } + + @Override + public Double getAverageRideHeight(Competitor competitor, TimePoint timePoint) { + return null; + } } 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 a6ab0f59476..5af89afdd88 100644 --- 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 @@ -76,6 +76,7 @@ import com.sap.sailing.domain.common.dto.LeaderboardRowDTO; import com.sap.sailing.domain.common.dto.LegEntryDTO; import com.sap.sailing.domain.common.dto.RaceColumnDTO; import com.sap.sailing.domain.common.impl.InvertibleComparatorAdapter; +import com.sap.sailing.domain.common.impl.MeterDistance; import com.sap.sailing.gwt.ui.actions.GetLeaderboardByNameAction; import com.sap.sailing.gwt.ui.client.Collator; import com.sap.sailing.gwt.ui.client.CompetitorSelectionChangeListener; @@ -102,6 +103,7 @@ import com.sap.sse.common.Util.Pair; import com.sap.sse.common.filter.BinaryOperator; import com.sap.sse.common.filter.Filter; import com.sap.sse.common.filter.FilterSet; +import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.gwt.client.ErrorReporter; import com.sap.sse.gwt.client.async.AsyncActionsExecutor; import com.sap.sse.gwt.client.async.MarkedAsyncCallback; @@ -972,10 +974,10 @@ public class LeaderboardPanel extends SimplePanel implements Component { + private class RaceCurrentSpeedOverGroundInKnots extends AbstractLastLegDetailField { @Override - protected Double get(LegEntryDTO lastLegDetail) { - return lastLegDetail.currentSpeedOverGroundInKnots; + protected Double getBeforeLastLegFinished(LegEntryDTO currentLegDetail) { + return currentLegDetail.currentSpeedOverGroundInKnots; + } + + @Override + protected Double getAfterLastLegFinished(LeaderboardRowDTO row) { + return new MeterDistance(row.totalDistanceTraveledInMeters).inTime(new MillisecondsDurationImpl((long) (1000.*row.totalTimeSailedInSeconds))).getKnots(); } } - private class CurrentRideHeightInMeters extends AbstractLastLegDetailField { + private class RaceCurrentRideHeightInMeters extends AbstractLastLegDetailField { @Override - protected Double get(LegEntryDTO lastLegDetail) { - return lastLegDetail.currentRideHeightInMeters; + protected Double getBeforeLastLegFinished(LegEntryDTO currentLegDetail) { + return currentLegDetail.currentRideHeightInMeters; + } + + @Override + protected Double getAfterLastLegFinished(LeaderboardRowDTO row) { + Double result = null; + LeaderboardEntryDTO fieldsForRace = row.fieldsByRaceColumnName.get(getRaceColumnName()); + if (fieldsForRace != null) { + result = fieldsForRace.averageRideHeightInMeters; + } + return result; } } } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java index c5be8205189..1fa1fd0fb0a 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java @@ -656,4 +656,9 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { public Iterable getAttachedRaceLogs() { return Collections.emptySet(); } + + @Override + public Double getAverageRideHeight(Competitor competitor, TimePoint timePoint) { + return null; + } } From 2072e3f624850f83fa99beba6bdf9fb44463a4e4 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Fri, 21 Oct 2016 14:28:39 +0200 Subject: [PATCH 21/31] Implemented range dimensions for the distance to starboard side at start and relative score for races of competitors --- .../data/TestLinearDoubleClusterGroup.java | 82 +++++++++++++++++++ .../datamining/SailingClusterGroups.java | 16 +++- .../data/HasRaceOfCompetitorContext.java | 7 ++ .../impl/data/LinearDoubleClusterGroup.java | 73 +++++++++++++++++ .../data/RaceOfCompetitorWithContext.java | 27 ++++++ 5 files changed, 201 insertions(+), 4 deletions(-) create mode 100644 java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/data/TestLinearDoubleClusterGroup.java create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LinearDoubleClusterGroup.java diff --git a/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/data/TestLinearDoubleClusterGroup.java b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/data/TestLinearDoubleClusterGroup.java new file mode 100644 index 00000000000..73a7de3ddb2 --- /dev/null +++ b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/data/TestLinearDoubleClusterGroup.java @@ -0,0 +1,82 @@ +package com.sap.sailing.datamining.impl.data; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +import org.junit.Before; +import org.junit.Test; + +import com.sap.sse.datamining.data.Cluster; +import com.sap.sse.datamining.data.ClusterGroup; +import com.sap.sse.datamining.impl.data.ClusterWithLowerAndUpperBoundaries; +import com.sap.sse.datamining.impl.data.ComparableClusterBoundary; +import com.sap.sse.datamining.impl.data.ComparisonStrategy; + +// TODO Move to sse bundle, after 49er analysis +public class TestLinearDoubleClusterGroup { + + private ClusterGroup hardPercentageClusterGroup; + private ClusterGroup softLinearClusterGroup; + + @Before + public void initialize() { + hardPercentageClusterGroup = new LinearDoubleClusterGroup(0.0, 1.0, 0.1, true); + softLinearClusterGroup = new LinearDoubleClusterGroup(0, 100, 10, false); + } + + @Test + public void testGetClusterForValueOutOfBounds() { + Cluster cluster = hardPercentageClusterGroup.getClusterFor(-0.01); + assertThat(cluster, nullValue()); + + cluster = hardPercentageClusterGroup.getClusterFor(1.01); + assertThat(cluster, nullValue()); + + cluster = softLinearClusterGroup.getClusterFor(-0.1); + Cluster expectedCluster = createCluster(0, 0, 10); + assertThat(cluster, is(expectedCluster)); + + cluster = softLinearClusterGroup.getClusterFor(100.1); + expectedCluster = createCluster(9, 0, 10); + assertThat(cluster, is(expectedCluster)); + } + + @Test + public void testGetClusterForBoundaryValues() { + Cluster cluster = hardPercentageClusterGroup.getClusterFor(0.0); + Cluster expectedCluster = createCluster(0, 0, 0.1); + assertThat(cluster, is(expectedCluster)); + + cluster = hardPercentageClusterGroup.getClusterFor(1.0); + expectedCluster = createCluster(9, 0, 0.1); + assertThat(cluster, is(expectedCluster)); + + cluster = softLinearClusterGroup.getClusterFor(0.0); + expectedCluster = createCluster(0, 0, 10); + assertThat(cluster, is(expectedCluster)); + + cluster = softLinearClusterGroup.getClusterFor(100.0); + expectedCluster = createCluster(9, 0, 10); + assertThat(cluster, is(expectedCluster)); + } + + @Test + public void testGetClusterFor() { + double value = -0.05; + double stepSize = 0.1; + for (int index = 0; index < 10; index++) { + value += stepSize; + Cluster cluster = hardPercentageClusterGroup.getClusterFor(value); + Cluster expectedCluster = createCluster(index, 0, stepSize); + assertThat(cluster, is(expectedCluster)); + } + } + + private Cluster createCluster(int index, double lowerBoundValue, double stepSize) { + ComparableClusterBoundary lowerBound = new ComparableClusterBoundary(lowerBoundValue + stepSize * index, ComparisonStrategy.GREATER_EQUALS_THAN); + ComparableClusterBoundary upperBound = new ComparableClusterBoundary(lowerBoundValue + stepSize * (index + 1), ComparisonStrategy.LOWER_THAN); + return new ClusterWithLowerAndUpperBoundaries<>(lowerBound, upperBound); + } + +} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingClusterGroups.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingClusterGroups.java index 888d6f848c2..24830d86e1a 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingClusterGroups.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingClusterGroups.java @@ -3,6 +3,7 @@ package com.sap.sailing.datamining; import java.util.ArrayList; import java.util.Collection; +import com.sap.sailing.datamining.impl.data.LinearDoubleClusterGroup; import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.impl.KnotSpeedImpl; import com.sap.sse.datamining.data.Cluster; @@ -17,7 +18,8 @@ import com.sap.sse.datamining.impl.data.LocalizedCluster; public class SailingClusterGroups { - private final ClusterGroup windStrengthInBeaufortCluster; + private final ClusterGroup windStrengthInBeaufortClusterGroup; + private final ClusterGroup percentageClusterGroup; public SailingClusterGroups() { Collection> clusters = new ArrayList<>(); @@ -98,11 +100,17 @@ public class SailingClusterGroups { lowerBound = new ComparableClusterBoundary(lowerBoundWindSpeed, ComparisonStrategy.GREATER_EQUALS_THAN); clusters.add(new LocalizedCluster("Bft12", new ClusterWithSingleBoundary(lowerBound))); - windStrengthInBeaufortCluster = new FixClusterGroup(clusters); + windStrengthInBeaufortClusterGroup = new FixClusterGroup(clusters); + + percentageClusterGroup = new LinearDoubleClusterGroup(0.0, 1.0, 0.1, true); } - public ClusterGroup getWindStrengthInBeaufortCluster() { - return windStrengthInBeaufortCluster; + public ClusterGroup getWindStrengthInBeaufortClusterGroup() { + return windStrengthInBeaufortClusterGroup; + } + + public ClusterGroup getPercentageClusterGroup() { + return percentageClusterGroup; } } 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 1103331021a..6c73e8ff52a 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 @@ -8,6 +8,7 @@ import com.sap.sailing.domain.common.Tack; import com.sap.sse.datamining.annotations.Connector; import com.sap.sse.datamining.annotations.Dimension; import com.sap.sse.datamining.annotations.Statistic; +import com.sap.sse.datamining.shared.impl.dto.ClusterDTO; public interface HasRaceOfCompetitorContext { @@ -23,6 +24,12 @@ public interface HasRaceOfCompetitorContext { @Dimension(messageKey="TackAtStart", ordinal=12) public Tack getTackAtStart() throws NoWindException; + @Dimension(messageKey="DistanceToStarboardSideAtStart", ordinal=13) + public ClusterDTO getPercentageClusterForDistanceToStarboardSideAtStart(); + + @Dimension(messageKey="RelativeScore", ordinal=14) + public ClusterDTO getPercentageClusterForRelativeScore(); + @Statistic(messageKey="DistanceAtStart", resultDecimals=2, ordinal=0) public Distance getDistanceToStartLineAtStart(); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LinearDoubleClusterGroup.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LinearDoubleClusterGroup.java new file mode 100644 index 00000000000..d7f9d426d29 --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LinearDoubleClusterGroup.java @@ -0,0 +1,73 @@ +package com.sap.sailing.datamining.impl.data; + +import java.util.HashMap; +import java.util.Map; + +import com.sap.sse.datamining.data.Cluster; +import com.sap.sse.datamining.data.ClusterGroup; +import com.sap.sse.datamining.impl.data.ClusterWithLowerAndUpperBoundaries; +import com.sap.sse.datamining.impl.data.ComparableClusterBoundary; +import com.sap.sse.datamining.impl.data.ComparisonStrategy; + +// TODO: Improve and move to com.sap.sse.datamining +public class LinearDoubleClusterGroup implements ClusterGroup { + private static final long serialVersionUID = 1559316450183865115L; + + private final double lowerBound; + private final double upperBound; + private final double stepSize; + private final boolean hardBounds; + + private final transient Map> clusterCache; + + public LinearDoubleClusterGroup(double lowerBound, double upperBound, double stepSize, boolean hardBounds) { + this.lowerBound = lowerBound; + this.upperBound = upperBound; + this.stepSize = stepSize; + this.hardBounds = hardBounds; + + clusterCache = new HashMap<>(); + } + + @Override + public Cluster getClusterFor(Double valueObject) { + double value = valueObject.doubleValue(); + if (value < lowerBound) { + return hardBounds ? null : getCluster(0); + } + if (value > upperBound) { + return hardBounds ? null : getCluster(getLastClusterIndex()); + } + + if (Math.abs(upperBound - value) < 0.0001) { + return getCluster(getLastClusterIndex()); + } + return getCluster((int) (value / stepSize)); + } + + private Cluster getCluster(int index) { + if (!clusterCache.containsKey(index)) { + ComparableClusterBoundary lowerBound = new ComparableClusterBoundary(this.lowerBound + stepSize * index, ComparisonStrategy.GREATER_EQUALS_THAN); + ComparableClusterBoundary upperBound = new ComparableClusterBoundary(this.lowerBound + stepSize * (index + 1), ComparisonStrategy.LOWER_THAN); + Cluster cluster = new ClusterWithLowerAndUpperBoundaries<>(lowerBound, upperBound); + clusterCache.put(index, cluster); + } + return clusterCache.get(index); + } + + private int getLastClusterIndex() { + double doubleIndex = upperBound / stepSize; + int index = (int) doubleIndex; + double fractionalPart = doubleIndex - index; + if (fractionalPart <= 0.0001) { + index--; + } + return index; + } + + @Override + public Class getClusterElementsType() { + return Double.class; + } + +} 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 89200db8ad1..5391ba917bf 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 @@ -2,6 +2,7 @@ package com.sap.sailing.datamining.impl.data; import java.util.concurrent.TimeUnit; +import com.sap.sailing.datamining.Activator; import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext; import com.sap.sailing.datamining.data.HasTrackedRaceContext; import com.sap.sailing.domain.base.Competitor; @@ -16,6 +17,9 @@ import com.sap.sailing.domain.tracking.Maneuver; 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; +import com.sap.sse.datamining.data.Cluster; +import com.sap.sse.datamining.shared.impl.dto.ClusterDTO; public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext { @@ -52,6 +56,17 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext { return startOfRace == null ? null : getTrackedRace().getTack(getCompetitor(), startOfRace); } + @Override + public ClusterDTO getPercentageClusterForDistanceToStarboardSideAtStart() { + Double normalizedDistance = getNormalizedDistanceToStarboardSideAtStart(); + if (normalizedDistance == null) { + return null; + } + + Cluster cluster = Activator.getClusterGroups().getPercentageClusterGroup().getClusterFor(normalizedDistance); + return new ClusterDTO(cluster.toString()); + } + @Override public Distance getDistanceToStartLineAtStart() { return getTrackedRace().getDistanceToStartLine(getCompetitor(), 0); @@ -71,6 +86,18 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext { return distance / length; } + @Override + public ClusterDTO getPercentageClusterForRelativeScore() { + Double rankAtFinish = getRankAtFinish(); + if (rankAtFinish == null) { + return null; + } + + int competitorCount = Util.size(getTrackedRace().getRace().getCompetitors()); + Cluster cluster = Activator.getClusterGroups().getPercentageClusterGroup().getClusterFor(rankAtFinish / competitorCount); + return new ClusterDTO(cluster.toString()); + } + @Override public Speed getSpeedWhenStarting() { return getTrackedRace().getSpeedWhenCrossingStartLine(getCompetitor()); From 02be736b122557eec1208dfff72e25e6fa9daa03 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 21 Oct 2016 14:36:04 +0200 Subject: [PATCH 22/31] fixed bug 3964 by calculating *race* average after last leg is finished Change-Id: Ib9852e87e473dbfae9c1a67407bb85338f8a979b --- .../common/dto/LeaderboardEntryDTO.java | 41 ++++++++++++++++ .../domain/common/dto/LeaderboardRowDTO.java | 25 ++++++++++ .../gwt/ui/leaderboard/LeaderboardPanel.java | 49 +++++-------------- 3 files changed, 77 insertions(+), 38 deletions(-) diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java index 390ec3246b1..9d525058fea 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java @@ -3,10 +3,13 @@ package com.sap.sailing.domain.common.dto; import java.io.Serializable; import java.util.List; +import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sailing.domain.common.RaceIdentifier; import com.sap.sailing.domain.common.Tack; +import com.sap.sailing.domain.common.impl.MeterDistance; import com.sap.sse.common.Duration; +import com.sap.sse.common.impl.MillisecondsDurationImpl; /** * Holds a single competitor's scoring details for a single race. It may optionally contain @@ -134,6 +137,44 @@ public class LeaderboardEntryDTO implements Serializable { public boolean hasScoreCorrection() { return totalPointsCorrected || (reasonForMaxPoints != null && reasonForMaxPoints != MaxPointsReason.NONE); } + + public Duration getTimeSailedInMillis() { + final Duration result; + if (legDetails != null) { + long timeInMilliseconds = 0; + for (LegEntryDTO legDetail : legDetails) { + if (legDetail != null) { + if (legDetail.distanceTraveledInMeters != null && legDetail.timeInMilliseconds != null) { + timeInMilliseconds += legDetail.timeInMilliseconds; + } else { + timeInMilliseconds = 0; + break; + } + } + } + result = new MillisecondsDurationImpl(timeInMilliseconds); + } else { + result = null; + } + return result; + } + + public Distance getDistanceTraveledInMeters() { + Distance result = null; + if (legDetails != null) { + for (LegEntryDTO legDetail : legDetails) { + if (legDetail != null) { + if (legDetail.distanceTraveledInMeters != null) { + if (result == null) { + result = Distance.NULL; + } + result = result.add(new MeterDistance(legDetail.distanceTraveledInMeters)); + } + } + } + } + return result; + } @Override public int hashCode() { diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardRowDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardRowDTO.java index 1f5036c8083..a5db8b41249 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardRowDTO.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardRowDTO.java @@ -4,6 +4,9 @@ import java.io.Serializable; import java.util.Date; import java.util.Map; +import com.sap.sailing.domain.common.Distance; +import com.sap.sse.common.Duration; + /** * Holds data about one competitor and all races represented by the owning {@link LeaderboardDTO leaderboard}. * @@ -117,6 +120,28 @@ public class LeaderboardRowDTO implements Serializable { return true; } + public Distance getDistanceTraveledInMeters(String raceColumnName) { + final Distance result; + LeaderboardEntryDTO fieldsForRace = fieldsByRaceColumnName.get(raceColumnName); + if (fieldsForRace != null) { + result = fieldsForRace.getDistanceTraveledInMeters(); + } else { + result = null; + } + return result; + } + + public Duration getTimeSailed(String raceColumnName) { + final Duration result; + LeaderboardEntryDTO fieldsForRace = fieldsByRaceColumnName.get(raceColumnName); + if (fieldsForRace != null) { + result = fieldsForRace.getTimeSailedInMillis(); + } else { + result = null; + } + return result; + } + @Override public String toString() { return "LeaderboardRowDTO for competitor "+competitor; 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 5af89afdd88..3d4056386e1 100644 --- 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 @@ -58,6 +58,7 @@ import com.google.gwt.view.client.MultiSelectionModel; import com.google.gwt.view.client.SelectionChangeEvent; import com.google.gwt.view.client.SelectionChangeEvent.Handler; import com.sap.sailing.domain.common.DetailType; +import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.common.InvertibleComparator; import com.sap.sailing.domain.common.LeaderboardNameConstants; import com.sap.sailing.domain.common.MaxPointsReason; @@ -76,7 +77,6 @@ import com.sap.sailing.domain.common.dto.LeaderboardRowDTO; import com.sap.sailing.domain.common.dto.LegEntryDTO; import com.sap.sailing.domain.common.dto.RaceColumnDTO; import com.sap.sailing.domain.common.impl.InvertibleComparatorAdapter; -import com.sap.sailing.domain.common.impl.MeterDistance; import com.sap.sailing.gwt.ui.actions.GetLeaderboardByNameAction; import com.sap.sailing.gwt.ui.client.Collator; import com.sap.sailing.gwt.ui.client.CompetitorSelectionChangeListener; @@ -98,12 +98,12 @@ import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil; import com.sap.sailing.gwt.ui.leaderboard.DetailTypeColumn.LegDetailField; import com.sap.sailing.gwt.ui.leaderboard.LeaderboardSettings.RaceColumnSelectionStrategies; import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO; +import com.sap.sse.common.Duration; import com.sap.sse.common.Util; import com.sap.sse.common.Util.Pair; import com.sap.sse.common.filter.BinaryOperator; import com.sap.sse.common.filter.Filter; import com.sap.sse.common.filter.FilterSet; -import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.gwt.client.ErrorReporter; import com.sap.sse.gwt.client.async.AsyncActionsExecutor; import com.sap.sse.gwt.client.async.MarkedAsyncCallback; @@ -1100,26 +1100,13 @@ public class LeaderboardPanel extends SimplePanel implements Component { @Override public Double get(LeaderboardRowDTO row) { - Double result = null; - LeaderboardEntryDTO fieldsForRace = row.fieldsByRaceColumnName.get(getRaceColumnName()); - if (fieldsForRace != null && fieldsForRace.legDetails != null) { - double distanceTraveledInMeters = 0; - long timeInMilliseconds = 0; - for (LegEntryDTO legDetail : fieldsForRace.legDetails) { - if (legDetail != null) { - if (legDetail.distanceTraveledInMeters != null && legDetail.timeInMilliseconds != null) { - distanceTraveledInMeters += legDetail.distanceTraveledInMeters; - timeInMilliseconds += legDetail.timeInMilliseconds; - } else { - distanceTraveledInMeters = 0; - timeInMilliseconds = 0; - break; - } - } - } - if (timeInMilliseconds != 0) { - result = distanceTraveledInMeters / (double) timeInMilliseconds * 1000 * 3600 / 1852; - } + final Distance distanceTraveledInMeters = row.getDistanceTraveledInMeters(getRaceColumnName()); + final Duration time = row.getTimeSailed(getRaceColumnName()); + final Double result; + if (distanceTraveledInMeters != null && time != null) { + result = distanceTraveledInMeters.inTime(time).getKnots(); + } else { + result = null; } return result; } @@ -1301,21 +1288,7 @@ public class LeaderboardPanel extends SimplePanel implements Component { @Override public Double get(LeaderboardRowDTO row) { - Double result = null; - LeaderboardEntryDTO fieldsForRace = row.fieldsByRaceColumnName.get(getRaceColumnName()); - if (fieldsForRace != null && fieldsForRace.legDetails != null) { - for (LegEntryDTO legDetail : fieldsForRace.legDetails) { - if (legDetail != null) { - if (legDetail.distanceTraveledInMeters != null) { - if (result == null) { - result = 0.0; - } - result += legDetail.distanceTraveledInMeters; - } - } - } - } - return result; + return row.getDistanceTraveledInMeters(getRaceColumnName()).getMeters(); } } @@ -1472,7 +1445,7 @@ public class LeaderboardPanel extends SimplePanel implements Component Date: Fri, 21 Oct 2016 14:49:43 +0200 Subject: [PATCH 23/31] migrated ride height from a double value to a Distance Change-Id: I15c18f90df384b0241f2ec5ef7e223ded96561d9 --- .../domain/common/tracking/BravoFix.java | 4 ++- .../common/tracking/impl/BravoFixImpl.java | 6 +++-- .../domain/test/mock/MockedTrackedRace.java | 2 +- ...ockedTrackedRaceWithStartTimeAndRanks.java | 2 +- .../impl/BravoFixTrackSerializationTest.java | 4 +-- .../impl/AbstractSimpleLeaderboardImpl.java | 9 ++++--- .../domain/tracking/BravoFixTrack.java | 5 ++-- .../tracking/TrackedLegOfCompetitor.java | 4 +-- .../sailing/domain/tracking/TrackedRace.java | 2 +- .../tracking/impl/BravoFixTrackImpl.java | 25 +++++++++++-------- .../impl/TrackedLegOfCompetitorImpl.java | 10 +++++--- .../domain/tracking/impl/TrackedRaceImpl.java | 4 +-- .../gwt/ui/test/MockedTrackedRace.java | 2 +- .../gwt/ui/server/SailingServiceImpl.java | 3 ++- .../trackfiles/test/BravoDataImportTest.java | 8 +++--- .../server/masterdata/DummyTrackedRace.java | 2 +- 16 files changed, 54 insertions(+), 38 deletions(-) diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/BravoFix.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/BravoFix.java index 73dd3504886..22564e68cc3 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/BravoFix.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/BravoFix.java @@ -1,5 +1,7 @@ package com.sap.sailing.domain.common.tracking; +import com.sap.sailing.domain.common.Distance; + /** * Specific {@link SensorFix} for bravo devices (http://www.bravosystems.es/). * @@ -12,5 +14,5 @@ public interface BravoFix extends SensorFix { * * @return the ride height */ - double getRideHeight(); + Distance getRideHeight(); } diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/BravoFixImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/BravoFixImpl.java index 99ba3015f75..c83402e7545 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/BravoFixImpl.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/BravoFixImpl.java @@ -1,5 +1,7 @@ package com.sap.sailing.domain.common.tracking.impl; +import com.sap.sailing.domain.common.Distance; +import com.sap.sailing.domain.common.impl.MeterDistance; import com.sap.sailing.domain.common.sensordata.BravoSensorDataMetadata; import com.sap.sailing.domain.common.tracking.BravoFix; import com.sap.sailing.domain.common.tracking.DoubleVectorFix; @@ -32,8 +34,8 @@ public class BravoFixImpl implements BravoFix { } @Override - public double getRideHeight() { - return fix.get(BravoSensorDataMetadata.INSTANCE.rideHeightColumn); + public Distance getRideHeight() { + return new MeterDistance(fix.get(BravoSensorDataMetadata.INSTANCE.rideHeightColumn)); } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java index d479e3bdacc..ba165f37cc1 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java @@ -1129,7 +1129,7 @@ public class MockedTrackedRace implements DynamicTrackedRace { } @Override - public Double getAverageRideHeight(Competitor competitor, TimePoint timePoint) { + public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) { return null; } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java index 0d05f85c50f..30cdeb5e6ac 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java @@ -683,7 +683,7 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace { } @Override - public Double getAverageRideHeight(Competitor competitor, TimePoint timePoint) { + public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) { return null; } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/tracking/impl/BravoFixTrackSerializationTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/tracking/impl/BravoFixTrackSerializationTest.java index 2a0f19e5877..0ab5678b885 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/tracking/impl/BravoFixTrackSerializationTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/tracking/impl/BravoFixTrackSerializationTest.java @@ -82,8 +82,8 @@ public class BravoFixTrackSerializationTest { assertRideHeight(track, testFixData.timePoint, testFixData.rideHeight); } - private void assertRideHeight(BravoFixTrack track, TimePoint timePoint, double expected) { - assertEquals(expected, track.getRideHeight(timePoint), 0.0); + private void assertRideHeight(BravoFixTrack track, TimePoint timePoint, double expectedRideHeightInMeters) { + assertEquals(expectedRideHeightInMeters, track.getRideHeight(timePoint).getMeters(), 0.0); } @SuppressWarnings("unchecked") 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 622447a5771..471d4f5ff89 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 @@ -1437,7 +1437,8 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race } else { entryDTO.timeSinceLastPositionFixInSeconds = null; } - entryDTO.averageRideHeightInMeters = trackedRace.getAverageRideHeight(competitor, timePoint); + final Distance averageRideHeight = trackedRace.getAverageRideHeight(competitor, timePoint); + entryDTO.averageRideHeightInMeters = averageRideHeight == null ? null : averageRideHeight.getMeters(); } if (addLegDetails && trackedRace != null) { try { @@ -1722,11 +1723,13 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race Double speedOverGroundInKnots; if (trackedLeg.hasFinishedLeg(timePoint)) { speedOverGroundInKnots = averageSpeedOverGround == null ? null : averageSpeedOverGround.getKnots(); - result.currentRideHeightInMeters = trackedLeg.getAverageRideHeight(timePoint); + final Distance averageRideHeight = trackedLeg.getAverageRideHeight(timePoint); + result.currentRideHeightInMeters = averageRideHeight == null ? null : averageRideHeight.getMeters(); } else { final SpeedWithBearing speedOverGround = trackedLeg.getSpeedOverGround(timePoint); speedOverGroundInKnots = speedOverGround == null ? null : speedOverGround.getKnots(); - result.currentRideHeightInMeters = trackedLeg.getRideHeight(timePoint); + final Distance rideHeight = trackedLeg.getRideHeight(timePoint); + result.currentRideHeightInMeters = rideHeight == null ? null : rideHeight.getMeters(); } result.currentSpeedOverGroundInKnots = speedOverGroundInKnots == null ? null : speedOverGroundInKnots; Distance distanceTraveled = trackedLeg.getDistanceTraveled(timePoint); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/BravoFixTrack.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/BravoFixTrack.java index fcd4163de00..c5b77ab96b1 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/BravoFixTrack.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/BravoFixTrack.java @@ -2,6 +2,7 @@ package com.sap.sailing.domain.tracking; import java.io.Serializable; +import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.common.tracking.BravoFix; import com.sap.sse.common.TimePoint; import com.sap.sse.common.WithID; @@ -22,7 +23,7 @@ public interface BravoFixTrack extends S * @return the ride height for the given {@link TimePoint} or null if the {@link TimePoint} is not in the range * where we have fixes for. */ - Double getRideHeight(TimePoint timePoint); + Distance getRideHeight(TimePoint timePoint); /** * Calculates the average ride height for the given time range. @@ -34,5 +35,5 @@ public interface BravoFixTrack extends S * @return the average ride height for the given time range or null if there are no fixes in the given * time range. */ - Double getAverageRideHeight(TimePoint from, TimePoint to); + Distance getAverageRideHeight(TimePoint from, TimePoint to); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedLegOfCompetitor.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedLegOfCompetitor.java index c4a8ab28c45..dc47af1cce1 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedLegOfCompetitor.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedLegOfCompetitor.java @@ -97,7 +97,7 @@ public interface TrackedLegOfCompetitor extends Serializable { * timePoint. If the competitor already completed the leg at timePoint and the respective * mark passing event was already received, the average ride height for the entire leg (and no further) is computed. */ - Double getAverageRideHeight(TimePoint timePoint); + Distance getAverageRideHeight(TimePoint timePoint); /** * @return null if the competitor hasn't started this leg yet, otherwise the fix where the maximum speed was @@ -237,7 +237,7 @@ public interface TrackedLegOfCompetitor extends Serializable { * timePoint, returns the current ride height for this time point. If the competitor has already * finished the leg, the ride height at the time the competitor finished the leg is returned. */ - Double getRideHeight(TimePoint at); + Distance getRideHeight(TimePoint at); /** * Computes the distance along the wind track to the wind-projected position of the race's overall leader. If leader diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java index 9d40a0d9df5..d864ae66e80 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java @@ -686,7 +686,7 @@ public interface TrackedRace extends Serializable, IsManagedByCache extends S } @Override - public Double getRideHeight(TimePoint timePoint) { + public Distance getRideHeight(TimePoint timePoint) { BravoFix fixAfter = getFirstFixAtOrAfter(timePoint); if (fixAfter != null && fixAfter.getTimePoint().compareTo(timePoint) == 0) { // exact match of timepoint -> no interpolation necessary @@ -54,17 +52,24 @@ public class BravoFixTrackImpl extends S } @Override - public Double getAverageRideHeight(TimePoint from, TimePoint to) { + public Distance getAverageRideHeight(TimePoint from, TimePoint to) { + final Distance result; lockForRead(); try { - Spliterator fixes = getFixes(from, true, to, true).spliterator(); - OptionalDouble average = StreamSupport.stream(fixes, false).mapToDouble(BravoFix::getRideHeight).average(); - if (average.isPresent()) { - return average.getAsDouble(); + Distance sum = Distance.NULL; + int count = 0; + for (final BravoFix fix : getFixes(from, true, to, true)) { + sum = sum.add(fix.getRideHeight()); + count++; + } + if (count > 0) { + result = sum.scale(1./count); + } else { + result = null; } } finally { unlockAfterRead(); } - return null; + return result; } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegOfCompetitorImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegOfCompetitorImpl.java index 538b24dd2e2..fba23c8af4a 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegOfCompetitorImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedLegOfCompetitorImpl.java @@ -183,7 +183,7 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor { } @Override - public Double getAverageRideHeight(TimePoint timePoint) { + public Distance getAverageRideHeight(TimePoint timePoint) { MarkPassing legStart = getMarkPassingForLegStart(); if (legStart != null) { BravoFixTrack track = getTrackedRace() @@ -676,15 +676,17 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor { } @Override - public Double getRideHeight(TimePoint at) { + public Distance getRideHeight(TimePoint at) { + final Distance result; if (hasStartedLeg(at)) { TimePoint timePoint =hasFinishedLeg(at) ? getMarkPassingForLegEnd().getTimePoint() : at; BravoFixTrack track = getTrackedRace() .> getSensorTrack(competitor, BravoFixTrack.TRACK_NAME); - return track == null ? null : track.getRideHeight(timePoint); + result = track == null ? null : track.getRideHeight(timePoint); } else { - return null; + result = null; } + return result; } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java index a5857993e06..bcb33ab5215 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java @@ -1539,8 +1539,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl } @Override - public Double getAverageRideHeight(Competitor competitor, TimePoint timePoint) { - final Double result; + public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) { + final Distance result; BravoFixTrack track = getSensorTrack(competitor, BravoFixTrack.TRACK_NAME); final Leg firstLeg; final TrackedLegOfCompetitor firstTrackedLeg; diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java index 1a3e75ffd46..00050caffca 100644 --- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java +++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java @@ -862,7 +862,7 @@ public class MockedTrackedRace implements DynamicTrackedRace { } @Override - public Double getAverageRideHeight(Competitor competitor, TimePoint timePoint) { + public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) { return null; } } 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 cdcc7d02788..ffcf6f905f3 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 @@ -2941,7 +2941,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S final BravoFixTrack bravoFixTrack = trackedRace .> getSensorTrack(competitor, BravoFixTrack.TRACK_NAME); if (bravoFixTrack != null) { - result = bravoFixTrack.getRideHeight(timePoint); + final Distance rideHeight = bravoFixTrack.getRideHeight(timePoint); + result = rideHeight == null ? null : rideHeight.getMeters(); } break; default: diff --git a/java/com.sap.sailing.server.trackfiles.test/src/com/sap/sailing/server/trackfiles/test/BravoDataImportTest.java b/java/com.sap.sailing.server.trackfiles.test/src/com/sap/sailing/server/trackfiles/test/BravoDataImportTest.java index 5fe5f150b5f..df3e94c8a5d 100644 --- a/java/com.sap.sailing.server.trackfiles.test/src/com/sap/sailing/server/trackfiles/test/BravoDataImportTest.java +++ b/java/com.sap.sailing.server.trackfiles.test/src/com/sap/sailing/server/trackfiles/test/BravoDataImportTest.java @@ -19,12 +19,12 @@ public class BravoDataImportTest { private final DoubleVectorFixImporter bravoDataImporter = new BravoDataImporterImpl(); private int callbackCallCount = 0; - private double sumRideHeight = 0.0; + private double sumRideHeightInMeters = 0.0; @Before public void setUp() { this.callbackCallCount = 0; - this.sumRideHeight = 0.0; + this.sumRideHeightInMeters = 0.0; } @Test @@ -51,12 +51,12 @@ public class BravoDataImportTest { bravoDataImporter.importFixes(importData.getInputStream(), (fixes, device) -> { for (DoubleVectorFix fix : fixes) { callbackCallCount++; - sumRideHeight += new BravoFixImpl(fix).getRideHeight(); + sumRideHeightInMeters += new BravoFixImpl(fix).getRideHeight().getMeters(); } }, "filename", "source"); Assert.assertEquals(importData.expectedFixesCount, callbackCallCount); Assert.assertEquals(importData.expectedAverageRideHeight, - callbackCallCount == 0 ? sumRideHeight : sumRideHeight / callbackCallCount, 0.00001); + callbackCallCount == 0 ? sumRideHeightInMeters : sumRideHeightInMeters / callbackCallCount, 0.00001); } private enum ImportData { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java index 1fa1fd0fb0a..f7c5d1462db 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java @@ -658,7 +658,7 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { } @Override - public Double getAverageRideHeight(Competitor competitor, TimePoint timePoint) { + public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) { return null; } } From 08bed0ed9ca0f29f469f721e40b5584d48b053fc Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Fri, 21 Oct 2016 16:28:47 +0200 Subject: [PATCH 24/31] Implemented a very dirty hack to format clusters without touching com.sap.sse.datamining --- .../data/TestPercentageClusterFormatter.java | 30 ++++ .../Sailing_StringMessages.properties | 1 + .../Sailing_StringMessages_de.properties | 1 + .../datamining/SailingClusterGroups.java | 9 ++ .../datamining/data/ClusterFormatter.java | 12 ++ .../data/HasRaceOfCompetitorContext.java | 2 +- .../impl/data/AbstractClusterFormatter.java | 143 ++++++++++++++++++ .../impl/data/PercentageClusterFormatter.java | 10 ++ .../data/RaceOfCompetitorWithContext.java | 11 +- 9 files changed, 214 insertions(+), 5 deletions(-) create mode 100644 java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/data/TestPercentageClusterFormatter.java create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/ClusterFormatter.java create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/AbstractClusterFormatter.java create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/PercentageClusterFormatter.java diff --git a/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/data/TestPercentageClusterFormatter.java b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/data/TestPercentageClusterFormatter.java new file mode 100644 index 00000000000..c2406269671 --- /dev/null +++ b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/data/TestPercentageClusterFormatter.java @@ -0,0 +1,30 @@ +package com.sap.sailing.datamining.impl.data; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import org.junit.Before; +import org.junit.Test; + +import com.sap.sse.datamining.data.Cluster; +import com.sap.sse.datamining.data.ClusterGroup; + +public class TestPercentageClusterFormatter { + + private ClusterGroup percentageClusterGroup; + private PercentageClusterFormatter formatter; + + @Before + public void initialize() { + percentageClusterGroup = new LinearDoubleClusterGroup(0.0, 1.0, 0.1, true); + formatter = new PercentageClusterFormatter(); + } + + @Test + public void testFormat() { + Cluster cluster = percentageClusterGroup.getClusterFor(0.05); + String formattedCluster = formatter.format(cluster); + assertThat(formattedCluster, is("[0% - 10%[")); + } + +} 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 02c56d2193d..0b0f2959f28 100644 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties @@ -47,6 +47,7 @@ Bft10=Storm Bft11=Violent storm Bft12=Hurricane RelativeScore=Relative Score (0 best; 1 worst) +RelativeScoreInPercent=Relative Score in % 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 e0a7d0556c3..a59cb34db07 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 @@ -47,6 +47,7 @@ Bft10=schwerer Sturm Bft11=orkanartiger Sturm Bft12=Orkan RelativeScore=Relative Wertung (0 am besten; 1 am schlechtesten) +RelativeScoreInPercent=Relative Wertung in % 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/SailingClusterGroups.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingClusterGroups.java index 24830d86e1a..c6404225ab3 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingClusterGroups.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingClusterGroups.java @@ -3,7 +3,9 @@ package com.sap.sailing.datamining; import java.util.ArrayList; import java.util.Collection; +import com.sap.sailing.datamining.data.ClusterFormatter; import com.sap.sailing.datamining.impl.data.LinearDoubleClusterGroup; +import com.sap.sailing.datamining.impl.data.PercentageClusterFormatter; import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.impl.KnotSpeedImpl; import com.sap.sse.datamining.data.Cluster; @@ -19,7 +21,9 @@ import com.sap.sse.datamining.impl.data.LocalizedCluster; public class SailingClusterGroups { private final ClusterGroup windStrengthInBeaufortClusterGroup; + private final ClusterGroup percentageClusterGroup; + private final ClusterFormatter percentageClusterFormatter; public SailingClusterGroups() { Collection> clusters = new ArrayList<>(); @@ -103,6 +107,7 @@ public class SailingClusterGroups { windStrengthInBeaufortClusterGroup = new FixClusterGroup(clusters); percentageClusterGroup = new LinearDoubleClusterGroup(0.0, 1.0, 0.1, true); + percentageClusterFormatter = new PercentageClusterFormatter(); } public ClusterGroup getWindStrengthInBeaufortClusterGroup() { @@ -112,5 +117,9 @@ public class SailingClusterGroups { public ClusterGroup getPercentageClusterGroup() { return percentageClusterGroup; } + + public ClusterFormatter getPercentageClusterFormatter() { + return percentageClusterFormatter; + } } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/ClusterFormatter.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/ClusterFormatter.java new file mode 100644 index 00000000000..821e13f3bec --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/ClusterFormatter.java @@ -0,0 +1,12 @@ +package com.sap.sailing.datamining.data; + +import java.io.Serializable; + +import com.sap.sse.datamining.data.Cluster; + +// TODO Move to sse bundle, after 49er analysis +public interface ClusterFormatter { + + String format(Cluster cluster); + +} 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 6c73e8ff52a..ca7d932145c 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 @@ -27,7 +27,7 @@ public interface HasRaceOfCompetitorContext { @Dimension(messageKey="DistanceToStarboardSideAtStart", ordinal=13) public ClusterDTO getPercentageClusterForDistanceToStarboardSideAtStart(); - @Dimension(messageKey="RelativeScore", ordinal=14) + @Dimension(messageKey="RelativeScoreInPercent", ordinal=14) public ClusterDTO getPercentageClusterForRelativeScore(); @Statistic(messageKey="DistanceAtStart", resultDecimals=2, ordinal=0) diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/AbstractClusterFormatter.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/AbstractClusterFormatter.java new file mode 100644 index 00000000000..f5fd3af28e9 --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/AbstractClusterFormatter.java @@ -0,0 +1,143 @@ +package com.sap.sailing.datamining.impl.data; + +import java.io.Serializable; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import com.sap.sailing.datamining.data.ClusterFormatter; +import com.sap.sse.datamining.data.Cluster; +import com.sap.sse.datamining.data.ClusterBoundary; +import com.sap.sse.datamining.impl.data.AbstractCluster; +import com.sap.sse.datamining.impl.data.AbstractClusterBoundary; +import com.sap.sse.datamining.impl.data.ClusterWithLowerAndUpperBoundaries; +import com.sap.sse.datamining.impl.data.ClusterWithSingleBoundary; +import com.sap.sse.datamining.impl.data.ComparisonStrategy; +import com.sap.sse.datamining.impl.data.LocalizedCluster; + +//TODO Clean and move to sse bundle after 49er analysis +public abstract class AbstractClusterFormatter implements ClusterFormatter { + + private static final char INFINITE = '\u221e'; + + private final ClusterBoundariesAccessor boundariesAccessor = new ClusterBoundariesAccessor(); + private final BoundaryValueAccessor valueAccessor = new BoundaryValueAccessor(); + + @Override + public String format(Cluster cluster) { + if (cluster instanceof LocalizedCluster) { + // TODO recursive call format(localizedCluster.getInnerCluster()) after 49er analysis + } + if (cluster instanceof ClusterWithSingleBoundary) { + return formatClusterWithSingleBoundary((ClusterWithSingleBoundary) cluster); + } + if (cluster instanceof ClusterWithLowerAndUpperBoundaries) { + return formatClusterWithLowerAndUpperBoundaries((ClusterWithLowerAndUpperBoundaries) cluster); + } + throw new IllegalArgumentException("Can't format clusters of type " + cluster.getClass().getName()); + } + + protected String formatClusterWithSingleBoundary(ClusterWithSingleBoundary cluster) { + List> boundaries = boundariesAccessor.getBoundaries(cluster); + if (boundaries == null) { + return ""; + } + + ClusterBoundary boundary = boundaries.get(0); + + StringBuilder builder = new StringBuilder(); + if (boundary.getStrategy() == ComparisonStrategy.LOWER_EQUALS_THAN || + boundary.getStrategy() == ComparisonStrategy.LOWER_THAN) { + builder.append("-" + INFINITE + " - "); + } + builder.append(formatBoundary(boundary)); + if (boundary.getStrategy() == ComparisonStrategy.GREATER_EQUALS_THAN || + boundary.getStrategy() == ComparisonStrategy.GREATER_THAN) { + builder.append(" - " + INFINITE); + } + return builder.toString(); + } + + protected String formatClusterWithLowerAndUpperBoundaries(ClusterWithLowerAndUpperBoundaries cluster) { + List> boundaries = boundariesAccessor.getBoundaries(cluster); + if (boundaries == null) { + return ""; + } + + return String.format("%s - %s", formatBoundary(boundaries.get(0)), formatBoundary(boundaries.get(1))); + } + + protected String formatBoundary(ClusterBoundary boundary) { + String value = formatValue(valueAccessor.getValue((AbstractClusterBoundary) boundary)); + if (value == null) { + return ""; + } + + StringBuilder builder = new StringBuilder(); + ComparisonStrategy strategy = boundary.getStrategy(); + if (strategy == ComparisonStrategy.GREATER_EQUALS_THAN || strategy == ComparisonStrategy.GREATER_THAN) { + builder.append(strategy.getSignifier()); + } + builder.append(value); + if (strategy == ComparisonStrategy.LOWER_EQUALS_THAN || strategy == ComparisonStrategy.LOWER_THAN) { + builder.append(strategy.getSignifier()); + } + return builder.toString(); + } + + protected abstract String formatValue(T value); + + //FIXME Please delete me + private class ClusterBoundariesAccessor { + + private static final String boundariesFieldName = "boundaries"; + + public List> getBoundaries(AbstractCluster cluster) { + List> boundaries = null; + Field boundariesField = null; + try { + boundariesField = AbstractCluster.class.getDeclaredField(boundariesFieldName); + boundariesField.setAccessible(true); + @SuppressWarnings("unchecked") + Collection> reflectedBoundaries = (Collection>) boundariesField.get(cluster); + boundaries = new ArrayList<>(); + for (ClusterBoundary boundary : reflectedBoundaries) { + boundaries.add(boundary); + } + } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { + } finally { + if (boundariesField != null) { + boundariesField.setAccessible(false); + } + } + return boundaries; + } + + } + + //FIXME Please delete me + private class BoundaryValueAccessor { + + private static final String valueFieldName = "boundaryValue"; + + @SuppressWarnings("unchecked") + public T getValue(AbstractClusterBoundary boundary) { + T value = null; + Field valueField = null; + try { + valueField = AbstractClusterBoundary.class.getDeclaredField(valueFieldName); + valueField.setAccessible(true); + value = (T) valueField.get(boundary); + } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { + } finally { + if (valueField != null) { + valueField.setAccessible(false); + } + } + return value; + } + + } + +} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/PercentageClusterFormatter.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/PercentageClusterFormatter.java new file mode 100644 index 00000000000..9423e734263 --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/PercentageClusterFormatter.java @@ -0,0 +1,10 @@ +package com.sap.sailing.datamining.impl.data; + +public class PercentageClusterFormatter extends AbstractClusterFormatter { + + @Override + protected String formatValue(Double value) { + return (int) (value * 100) + "%"; + } + +} 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 5391ba917bf..92f91e7ec27 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 @@ -3,6 +3,7 @@ package com.sap.sailing.datamining.impl.data; import java.util.concurrent.TimeUnit; import com.sap.sailing.datamining.Activator; +import com.sap.sailing.datamining.SailingClusterGroups; import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext; import com.sap.sailing.datamining.data.HasTrackedRaceContext; import com.sap.sailing.domain.base.Competitor; @@ -63,8 +64,9 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext { return null; } - Cluster cluster = Activator.getClusterGroups().getPercentageClusterGroup().getClusterFor(normalizedDistance); - return new ClusterDTO(cluster.toString()); + SailingClusterGroups clusterGroups = Activator.getClusterGroups(); + Cluster cluster = clusterGroups.getPercentageClusterGroup().getClusterFor(normalizedDistance); + return new ClusterDTO(clusterGroups.getPercentageClusterFormatter().format(cluster)); } @Override @@ -94,8 +96,9 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext { } int competitorCount = Util.size(getTrackedRace().getRace().getCompetitors()); - Cluster cluster = Activator.getClusterGroups().getPercentageClusterGroup().getClusterFor(rankAtFinish / competitorCount); - return new ClusterDTO(cluster.toString()); + SailingClusterGroups clusterGroups = Activator.getClusterGroups(); + Cluster cluster = clusterGroups.getPercentageClusterGroup().getClusterFor(rankAtFinish / competitorCount); + return new ClusterDTO(clusterGroups.getPercentageClusterFormatter().format(cluster)); } @Override From a885d3a32c118d873ea98f63e9c4f42d1ef6cd41 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Fri, 21 Oct 2016 18:06:36 +0200 Subject: [PATCH 25/31] Implemented the dimension relative score in race in % for legs of competitors --- .../Sailing_StringMessages.properties | 1 + .../Sailing_StringMessages_de.properties | 1 + .../data/HasTrackedLegOfCompetitorContext.java | 4 ++++ .../datamining/data/HasTrackedRaceContext.java | 6 ++++++ .../impl/data/RaceOfCompetitorWithContext.java | 15 ++++----------- .../data/TrackedLegOfCompetitorWithContext.java | 16 ++++++++++++++++ .../impl/data/TrackedRaceWithContext.java | 15 +++++++++++++++ 7 files changed, 47 insertions(+), 11 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 0b0f2959f28..f74b5d7cb7c 100644 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties @@ -48,6 +48,7 @@ Bft11=Violent storm Bft12=Hurricane RelativeScore=Relative Score (0 best; 1 worst) RelativeScoreInPercent=Relative Score in % +RelativeScoreInRaceInPercent=Relative Score in Race in % 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 a59cb34db07..4990f1d020d 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 @@ -48,6 +48,7 @@ Bft11=orkanartiger Sturm Bft12=Orkan RelativeScore=Relative Wertung (0 am besten; 1 am schlechtesten) RelativeScoreInPercent=Relative Wertung in % +RelativeScoreInRaceInPercent=Relative Wertung im Rennen in % 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/HasTrackedLegOfCompetitorContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java index 16dc536da6d..2756957d7ec 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 @@ -6,6 +6,7 @@ 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; +import com.sap.sse.datamining.shared.impl.dto.ClusterDTO; public interface HasTrackedLegOfCompetitorContext { @@ -16,6 +17,9 @@ public interface HasTrackedLegOfCompetitorContext { @Dimension(messageKey="CompetitorSearchTag", ordinal=11) // TODO Clean me: Move Dimension to Competitor when possible public String getCompetitorSearchTag(); + + @Dimension(messageKey="RelativeScoreInRaceInPercent", ordinal=12) + public ClusterDTO getPercentageClusterForRelativeScoreInRace(); @Connector(messageKey="Competitor") public Competitor getCompetitor(); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java index aed8f28d024..aee4b7104b0 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java @@ -1,6 +1,7 @@ package com.sap.sailing.datamining.data; import com.sap.sailing.domain.base.BoatClass; +import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.RaceDefinition; @@ -44,4 +45,9 @@ public interface HasTrackedRaceContext { @Statistic(messageKey="NumberOfMarkFixes", resultDecimals=0, ordinal=1) public int getNumberOfMarkFixes(); + // Convenience methods for race dependent calculation to avoid code duplication + public Double getRelativeScoreForCompetitor(Competitor competitor); + + public Double getRankAtFinishForCompetitor(Competitor competitor); + } \ No newline at end of file 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 92f91e7ec27..455634920b2 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 @@ -18,7 +18,6 @@ import com.sap.sailing.domain.tracking.Maneuver; 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; import com.sap.sse.datamining.data.Cluster; import com.sap.sse.datamining.shared.impl.dto.ClusterDTO; @@ -90,14 +89,13 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext { @Override public ClusterDTO getPercentageClusterForRelativeScore() { - Double rankAtFinish = getRankAtFinish(); - if (rankAtFinish == null) { + Double relativeScore = getTrackedRaceContext().getRelativeScoreForCompetitor(getCompetitor()); + if (relativeScore == null) { return null; } - int competitorCount = Util.size(getTrackedRace().getRace().getCompetitors()); SailingClusterGroups clusterGroups = Activator.getClusterGroups(); - Cluster cluster = clusterGroups.getPercentageClusterGroup().getClusterFor(rankAtFinish / competitorCount); + Cluster cluster = clusterGroups.getPercentageClusterGroup().getClusterFor(relativeScore); return new ClusterDTO(clusterGroups.getPercentageClusterFormatter().format(cluster)); } @@ -158,15 +156,10 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext { @Override public Double getRankGainsOrLossesBetweenFirstMarkAndFinish() { Double rankAtFirstMark = getRankAtFirstMark(); - Double rankAtFinish = getRankAtFinish(); + Double rankAtFinish = getTrackedRaceContext().getRankAtFinishForCompetitor(getCompetitor()); return rankAtFirstMark != null && rankAtFinish != null ? rankAtFirstMark - rankAtFinish : null; } - private Double getRankAtFinish() { - int rank = getTrackedRace().getRank(getCompetitor(), getTrackedRace().getEndOfTracking()); - return rank == 0 ? null : Double.valueOf(rank); - } - @Override public int getNumberOfManeuvers() { return getNumberOfTacks() + getNumberOfJibes(); 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 261947cb303..e50cae7962a 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 @@ -1,5 +1,7 @@ package com.sap.sailing.datamining.impl.data; +import com.sap.sailing.datamining.Activator; +import com.sap.sailing.datamining.SailingClusterGroups; import com.sap.sailing.datamining.data.HasTrackedLegContext; import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; import com.sap.sailing.domain.base.Competitor; @@ -9,6 +11,8 @@ 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; +import com.sap.sse.datamining.data.Cluster; +import com.sap.sse.datamining.shared.impl.dto.ClusterDTO; public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompetitorContext { @@ -48,6 +52,18 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti return getCompetitor().getSearchTag(); } + @Override + public ClusterDTO getPercentageClusterForRelativeScoreInRace() { + Double relativeScore = getTrackedLegContext().getTrackedRaceContext().getRelativeScoreForCompetitor(getCompetitor()); + if (relativeScore == null) { + return null; + } + + SailingClusterGroups clusterGroups = Activator.getClusterGroups(); + Cluster cluster = clusterGroups.getPercentageClusterGroup().getClusterFor(relativeScore); + return new ClusterDTO(clusterGroups.getPercentageClusterFormatter().format(cluster)); + } + @Override public Distance getDistanceTraveled() { TimePoint timePoint = getTrackedLegContext().getTrackedRaceContext().getTrackedRace().getEndOfTracking(); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java index d899829ec8d..6691d52a081 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java @@ -125,5 +125,20 @@ public class TrackedRaceWithContext implements HasTrackedRaceContext { } return number; } + + // Convenience methods for race dependent calculation to avoid code duplication + public Double getRelativeScoreForCompetitor(Competitor competitor) { + Double rankAtFinish = getRankAtFinishForCompetitor(competitor); + if (rankAtFinish == null) { + return null; + } + return rankAtFinish / Util.size(getTrackedRace().getRace().getCompetitors()); + } + + @Override + public Double getRankAtFinishForCompetitor(Competitor competitor) { + int rank = getTrackedRace().getRank(competitor, getTrackedRace().getEndOfTracking()); + return rank == 0 ? null : Double.valueOf(rank); + } } \ No newline at end of file From 18bb8a8061c7fcf1bb1be1c64f0eb136ab781c0a Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sat, 22 Oct 2016 10:05:40 +0200 Subject: [PATCH 26/31] Fixed the recovering of polars for existing races after com.sap.sailing.polars restart --- .../sap/sailing/polars/impl/PolarDataServiceImpl.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java index 8a0b9d74bcc..72902780367 100755 --- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java +++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java @@ -35,6 +35,7 @@ import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.domain.polars.PolarsChangedListener; +import com.sap.sailing.domain.tracking.GPSFixTrack; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.polars.PolarDataOperation; import com.sap.sailing.polars.mining.BearingClusterGroup; @@ -236,8 +237,14 @@ public class PolarDataServiceImpl implements PolarDataService, @Override public void insertExistingFixes(TrackedRace trackedRace) { for (Competitor competitor : trackedRace.getRace().getCompetitors()) { - for (GPSFixMoving fix : trackedRace.getTrack(competitor).getFixes()) { - competitorPositionChanged(fix, competitor, trackedRace); + GPSFixTrack track = trackedRace.getTrack(competitor); + track.lockForRead(); + try { + for (GPSFixMoving fix : track.getFixes()) { + competitorPositionChanged(fix, competitor, trackedRace); + } + } finally { + track.unlockAfterRead(); } } } From 67d766db74f8ce2995dc723b413358fd9d845cd5 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sat, 22 Oct 2016 11:13:45 +0200 Subject: [PATCH 27/31] Implemented a dimension and statistic regarding the advantageous end of line of races --- .../Sailing_StringMessages.properties | 5 +-- .../Sailing_StringMessages_de.properties | 5 +-- .../data/HasRaceOfCompetitorContext.java | 26 +++++++------- .../data/HasTrackedRaceContext.java | 6 +++- .../data/RaceOfCompetitorWithContext.java | 36 +++++++++++++++++++ .../impl/data/TrackedRaceWithContext.java | 8 +++++ 6 files changed, 68 insertions(+), 18 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 f74b5d7cb7c..04d00789437 100644 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties @@ -78,5 +78,6 @@ PassingSide=Passing Side TackAtStart=Tack at Start SpeedTenSecondsAfterStart=Speed 10s After Start RankThirtySecondsAfterStart=Rank 30s After Start -StartAdvantage=Start Advantage -RankAfterHalfOfTheFirstLeg=Rank after the half of the first leg \ No newline at end of file +WindwardDistanceToAdvantageousEndOfLine=Windward Distance to Advantageous End of Line +RankAfterHalfOfTheFirstLeg=Rank after the half of the first leg +AdvantageousEndOfLine=Advantageous End of Line \ No newline at end of file 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 4990f1d020d..9d09ed600d0 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 @@ -78,5 +78,6 @@ PassingSide=Passierende Seite TackAtStart=Startbug SpeedTenSecondsAfterStart=Geschwindigkeit 10s nach dem Startzeitpunkt RankThirtySecondsAfterStart=Absolute Platzierung 30s nach dem Startzeitpunkt -StartAdvantage=Startvorteil -RankAfterHalfOfTheFirstLeg=Platzierung nach der Hälfte des ersten Schenkels \ No newline at end of file +WindwardDistanceToAdvantageousEndOfLine=Windwärtige Distanz zum Bevorteilten Ende der Startlinie +RankAfterHalfOfTheFirstLeg=Platzierung nach der Hälfte des ersten Schenkels +AdvantageousEndOfLine=Bevorteiltes Ende der Startlinie \ 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 ca7d932145c..97bde57e8e8 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 @@ -36,40 +36,40 @@ public interface HasRaceOfCompetitorContext { @Statistic(messageKey="DistanceToStarboardSideAtStart", resultDecimals=2, ordinal=1) public Double getNormalizedDistanceToStarboardSideAtStart(); -// @Statistic(messageKey="StartAdvantage", resultDecimals=2, ordinal=2) -// public Double getNormalizedDistanceToFavoredEndAtStart(); + @Statistic(messageKey="WindwardDistanceToAdvantageousEndOfLine", resultDecimals=2, ordinal=2) + public Distance getWindwardDistanceToAdvantageousLineEndAtStart(); - @Connector(messageKey="SpeedWhenStarting", ordinal=2) + @Connector(messageKey="SpeedWhenStarting", ordinal=3) public Speed getSpeedWhenStarting(); - @Connector(messageKey="SpeedTenSecondsBeforeStart", ordinal=3) + @Connector(messageKey="SpeedTenSecondsBeforeStart", ordinal=4) public Speed getSpeedTenSecondsBeforeStart(); - @Connector(messageKey="SpeedTenSecondsAfterStart", ordinal=4) + @Connector(messageKey="SpeedTenSecondsAfterStart", ordinal=5) public Speed getSpeedTenSecondsAfterStart(); - @Statistic(messageKey="RankThirtySecondsAfterStart", resultDecimals=2, ordinal=5) + @Statistic(messageKey="RankThirtySecondsAfterStart", resultDecimals=2, ordinal=6) public Double getRankThirtySecondsAfterStart(); - @Statistic(messageKey="RankAfterHalfOfTheFirstLeg", resultDecimals=2, ordinal=6) + @Statistic(messageKey="RankAfterHalfOfTheFirstLeg", resultDecimals=2, ordinal=7) public Double getRankAfterHalfOfTheFirstLeg(); - @Statistic(messageKey="RankAtFirstMark", resultDecimals=2, ordinal=6) + @Statistic(messageKey="RankAtFirstMark", resultDecimals=2, ordinal=8) public Double getRankAtFirstMark(); - @Statistic(messageKey="RankGainsOrLossesBetweenFirstMarkAndFinish", resultDecimals=2, ordinal=7) + @Statistic(messageKey="RankGainsOrLossesBetweenFirstMarkAndFinish", resultDecimals=2, ordinal=9) public Double getRankGainsOrLossesBetweenFirstMarkAndFinish(); - @Statistic(messageKey="NumberOfManeuvers", resultDecimals=0, ordinal=8) + @Statistic(messageKey="NumberOfManeuvers", resultDecimals=0, ordinal=10) public int getNumberOfManeuvers(); - @Statistic(messageKey="NumberOfTacks", resultDecimals=2, ordinal=9) + @Statistic(messageKey="NumberOfTacks", resultDecimals=2, ordinal=11) public int getNumberOfTacks(); - @Statistic(messageKey="NumberOfJibes", resultDecimals=2, ordinal=10) + @Statistic(messageKey="NumberOfJibes", resultDecimals=2, ordinal=12) public int getNumberOfJibes(); - @Statistic(messageKey="NumberOfPenaltyCircles", resultDecimals=2, ordinal=11) + @Statistic(messageKey="NumberOfPenaltyCircles", resultDecimals=2, ordinal=13) public int getNumberOfPenaltyCircles(); } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java index aee4b7104b0..059a000e659 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java @@ -6,6 +6,7 @@ import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Regatta; +import com.sap.sailing.domain.common.NauticalSide; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sse.datamining.annotations.Connector; import com.sap.sse.datamining.annotations.Dimension; @@ -36,7 +37,10 @@ public interface HasTrackedRaceContext { @Dimension(messageKey="Year", ordinal=2) public Integer getYear(); - @Dimension(messageKey="IsTracked", ordinal=6) + @Dimension(messageKey="AdvantageousEndOfLine", ordinal=6) + public NauticalSide getAdvantageousEndOfLine(); + + @Dimension(messageKey="IsTracked", ordinal=7) public Boolean isTracked(); @Statistic(messageKey="NumberOfCompetitorFixes", resultDecimals=0, ordinal=0) 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 455634920b2..82c38d7dad6 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 @@ -8,15 +8,23 @@ import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext; import com.sap.sailing.datamining.data.HasTrackedRaceContext; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Course; +import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.Waypoint; import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.common.ManeuverType; import com.sap.sailing.domain.common.NoWindException; +import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.Tack; +import com.sap.sailing.domain.common.tracking.GPSFix; +import com.sap.sailing.domain.common.tracking.GPSFixMoving; +import com.sap.sailing.domain.tracking.GPSFixTrack; +import com.sap.sailing.domain.tracking.LineDetails; import com.sap.sailing.domain.tracking.Maneuver; +import com.sap.sailing.domain.tracking.TrackedLeg; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.domain.tracking.WindPositionMode; import com.sap.sse.common.TimePoint; import com.sap.sse.datamining.data.Cluster; import com.sap.sse.datamining.shared.impl.dto.ClusterDTO; @@ -87,6 +95,34 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext { return distance / length; } + @Override + public Distance getWindwardDistanceToAdvantageousLineEndAtStart() { + TrackedRace trackedRace = getTrackedRace(); + TimePoint startOfRace = trackedRace.getStartOfRace(); + LineDetails startLine = trackedRace.getStartLine(startOfRace); + Mark advantageousMark = null; + switch (startLine.getAdvantageousSideWhileApproachingLine()) { + case PORT: + advantageousMark = startLine.getPortMarkWhileApproachingLine(); + break; + case STARBOARD: + advantageousMark = startLine.getStarboardMarkWhileApproachingLine(); + break; + } + if (advantageousMark == null) { + return null; + } + + GPSFixTrack advantageousMarkTrack = trackedRace.getOrCreateTrack(advantageousMark); + Position advantageousMarkPosition = advantageousMarkTrack.getEstimatedPosition(startOfRace, false); + GPSFixTrack competitorTrack = trackedRace.getTrack(getCompetitor()); + Position competitorPosition = competitorTrack.getEstimatedPosition(startOfRace, false); + + TrackedLeg trackedLeg = trackedRace.getTrackedLeg(trackedRace.getRace().getCourse().getFirstLeg()); + Distance distance = trackedLeg.getWindwardDistance(competitorPosition, advantageousMarkPosition, startOfRace, WindPositionMode.LEG_MIDDLE); + return distance; + } + @Override public ClusterDTO getPercentageClusterForRelativeScore() { Double relativeScore = getTrackedRaceContext().getRelativeScoreForCompetitor(getCompetitor()); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java index 6691d52a081..a7e4a0893c0 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java @@ -11,9 +11,11 @@ import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Regatta; +import com.sap.sailing.domain.common.NauticalSide; import com.sap.sailing.domain.common.tracking.GPSFix; import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.tracking.GPSFixTrack; +import com.sap.sailing.domain.tracking.LineDetails; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util; @@ -90,6 +92,12 @@ public class TrackedRaceWithContext implements HasTrackedRaceContext { calendar.setTime(time.asDate()); return calendar.get(Calendar.YEAR); } + + @Override + public NauticalSide getAdvantageousEndOfLine() { + LineDetails startLine = getTrackedRace().getStartLine(getTrackedRace().getStartOfRace()); + return startLine.getAdvantageousSideWhileApproachingLine(); + } @Override public Boolean isTracked() { From 1d2906d5c5333696f6dc1329bfab673a3da1e3fd Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sat, 22 Oct 2016 11:16:31 +0200 Subject: [PATCH 28/31] Errors during the polar reconstruction are now logged --- .../src/com/sap/sailing/server/impl/RacingEventServiceImpl.java | 2 ++ 1 file changed, 2 insertions(+) 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 3f36f29fd26..06c93aeca4a 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 @@ -3484,6 +3484,8 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes trackedRace.setPolarDataService(service); service.insertExistingFixes(trackedRace); } + } catch (Throwable e) { + logger.log(Level.SEVERE, "Error reconstructing the polars for tracked races", e); } finally { trackedRegatta.unlockTrackedRacesAfterRead(); } From 03bcdb2ec64536d4b61939f4091fa55e5600e7d4 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sat, 22 Oct 2016 12:13:20 +0200 Subject: [PATCH 29/31] Implemented KPI for the time a competitor spent in a leg --- .../stringmessages/Sailing_StringMessages.properties | 3 ++- .../Sailing_StringMessages_de.properties | 3 ++- .../data/HasTrackedLegOfCompetitorContext.java | 3 +++ .../impl/data/TrackedLegOfCompetitorWithContext.java | 11 +++++++++++ 4 files changed, 18 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 04d00789437..c05cc401159 100644 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties @@ -80,4 +80,5 @@ SpeedTenSecondsAfterStart=Speed 10s After Start RankThirtySecondsAfterStart=Rank 30s After Start WindwardDistanceToAdvantageousEndOfLine=Windward Distance to Advantageous End of Line RankAfterHalfOfTheFirstLeg=Rank after the half of the first leg -AdvantageousEndOfLine=Advantageous End of Line \ No newline at end of file +AdvantageousEndOfLine=Advantageous End of Line +TimeSpentInSeconds=Time Spent in Seconds \ No newline at end of file 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 9d09ed600d0..a12a8452ec2 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 @@ -80,4 +80,5 @@ SpeedTenSecondsAfterStart=Geschwindigkeit 10s nach dem Startzeitpunkt RankThirtySecondsAfterStart=Absolute Platzierung 30s nach dem Startzeitpunkt WindwardDistanceToAdvantageousEndOfLine=Windwärtige Distanz zum Bevorteilten Ende der Startlinie RankAfterHalfOfTheFirstLeg=Platzierung nach der Hälfte des ersten Schenkels -AdvantageousEndOfLine=Bevorteiltes Ende der Startlinie \ No newline at end of file +AdvantageousEndOfLine=Bevorteiltes Ende der Startlinie +TimeSpentInSeconds=Benötigte Zeit in Sekunden \ No newline at end of file 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 2756957d7ec..4f5cb3a3ea9 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 @@ -35,5 +35,8 @@ public interface HasTrackedLegOfCompetitorContext { @Statistic(messageKey="AbsoluteRank", resultDecimals=2, ordinal=3) public Double getAbsoluteRank(); + + @Statistic(messageKey="TimeSpentInSeconds", resultDecimals=0, ordinal=4) + public Long getTimeTakenInSeconds(); } \ 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 e50cae7962a..09e719dbe9d 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 @@ -110,4 +110,15 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti return rankAtFinish; } + @Override + public Long getTimeTakenInSeconds() { + TimePoint startTime = getTrackedLegOfCompetitor().getStartTime(); + TimePoint finishTime = getTrackedLegOfCompetitor().getFinishTime(); + if (startTime == null || finishTime == null) { + return null; + } + + return (finishTime.asMillis() - startTime.asMillis()) / 1000; + } + } From 201c65cc3758bf243990355c8c71bde4ca667770 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sat, 22 Oct 2016 14:16:37 +0200 Subject: [PATCH 30/31] Improved the LinearDoubleClusterGroup --- .../data/TestLinearDoubleClusterGroup.java | 44 +++++---- .../impl/data/LinearDoubleClusterGroup.java | 91 +++++++++++++------ 2 files changed, 88 insertions(+), 47 deletions(-) diff --git a/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/data/TestLinearDoubleClusterGroup.java b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/data/TestLinearDoubleClusterGroup.java index 73a7de3ddb2..0394eafa2a5 100644 --- a/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/data/TestLinearDoubleClusterGroup.java +++ b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/data/TestLinearDoubleClusterGroup.java @@ -8,16 +8,16 @@ import org.junit.Before; import org.junit.Test; import com.sap.sse.datamining.data.Cluster; -import com.sap.sse.datamining.data.ClusterGroup; import com.sap.sse.datamining.impl.data.ClusterWithLowerAndUpperBoundaries; +import com.sap.sse.datamining.impl.data.ClusterWithSingleBoundary; import com.sap.sse.datamining.impl.data.ComparableClusterBoundary; import com.sap.sse.datamining.impl.data.ComparisonStrategy; // TODO Move to sse bundle, after 49er analysis public class TestLinearDoubleClusterGroup { - private ClusterGroup hardPercentageClusterGroup; - private ClusterGroup softLinearClusterGroup; + private LinearDoubleClusterGroup hardPercentageClusterGroup; + private LinearDoubleClusterGroup softLinearClusterGroup; @Before public void initialize() { @@ -34,49 +34,53 @@ public class TestLinearDoubleClusterGroup { assertThat(cluster, nullValue()); cluster = softLinearClusterGroup.getClusterFor(-0.1); - Cluster expectedCluster = createCluster(0, 0, 10); + Cluster expectedCluster = createCluster(softLinearClusterGroup.getStepSize(), ComparisonStrategy.LOWER_THAN); assertThat(cluster, is(expectedCluster)); cluster = softLinearClusterGroup.getClusterFor(100.1); - expectedCluster = createCluster(9, 0, 10); + expectedCluster = createCluster(softLinearClusterGroup.getUpperGroupBound() - softLinearClusterGroup.getStepSize(), ComparisonStrategy.GREATER_EQUALS_THAN); assertThat(cluster, is(expectedCluster)); } @Test public void testGetClusterForBoundaryValues() { Cluster cluster = hardPercentageClusterGroup.getClusterFor(0.0); - Cluster expectedCluster = createCluster(0, 0, 0.1); + Cluster expectedCluster = createCluster(hardPercentageClusterGroup.getLowerGroupBound(), ComparisonStrategy.GREATER_EQUALS_THAN, + hardPercentageClusterGroup.getLowerGroupBound() + hardPercentageClusterGroup.getStepSize(), ComparisonStrategy.LOWER_THAN); assertThat(cluster, is(expectedCluster)); cluster = hardPercentageClusterGroup.getClusterFor(1.0); - expectedCluster = createCluster(9, 0, 0.1); + expectedCluster = createCluster(hardPercentageClusterGroup.getUpperGroupBound() - hardPercentageClusterGroup.getStepSize(), ComparisonStrategy.GREATER_EQUALS_THAN, + hardPercentageClusterGroup.getUpperGroupBound(), ComparisonStrategy.LOWER_EQUALS_THAN); assertThat(cluster, is(expectedCluster)); cluster = softLinearClusterGroup.getClusterFor(0.0); - expectedCluster = createCluster(0, 0, 10); + expectedCluster = createCluster(softLinearClusterGroup.getStepSize(), ComparisonStrategy.LOWER_THAN); assertThat(cluster, is(expectedCluster)); cluster = softLinearClusterGroup.getClusterFor(100.0); - expectedCluster = createCluster(9, 0, 10); + expectedCluster = createCluster(softLinearClusterGroup.getUpperGroupBound() - softLinearClusterGroup.getStepSize(), ComparisonStrategy.GREATER_EQUALS_THAN); assertThat(cluster, is(expectedCluster)); } @Test public void testGetClusterFor() { - double value = -0.05; - double stepSize = 0.1; - for (int index = 0; index < 10; index++) { - value += stepSize; - Cluster cluster = hardPercentageClusterGroup.getClusterFor(value); - Cluster expectedCluster = createCluster(index, 0, stepSize); - assertThat(cluster, is(expectedCluster)); - } + LinearDoubleClusterGroup clusterGroup = softLinearClusterGroup; + double value = (clusterGroup.getUpperGroupBound() + clusterGroup.getStepSize()) / 2; + Cluster cluster = clusterGroup.getClusterFor(value); + Cluster expectedCluster = createCluster(clusterGroup.getUpperGroupBound() / 2, ComparisonStrategy.GREATER_EQUALS_THAN, + (clusterGroup.getUpperGroupBound() / 2) + clusterGroup.getStepSize(), ComparisonStrategy.LOWER_THAN); + assertThat(cluster, is(expectedCluster)); } - private Cluster createCluster(int index, double lowerBoundValue, double stepSize) { - ComparableClusterBoundary lowerBound = new ComparableClusterBoundary(lowerBoundValue + stepSize * index, ComparisonStrategy.GREATER_EQUALS_THAN); - ComparableClusterBoundary upperBound = new ComparableClusterBoundary(lowerBoundValue + stepSize * (index + 1), ComparisonStrategy.LOWER_THAN); + private Cluster createCluster(double lowerBoundValue, ComparisonStrategy lowerComparisonStrategy, double upperBoundValue, ComparisonStrategy upperComparisonStrategy) { + ComparableClusterBoundary lowerBound = new ComparableClusterBoundary<>(lowerBoundValue, lowerComparisonStrategy); + ComparableClusterBoundary upperBound = new ComparableClusterBoundary<>(upperBoundValue, upperComparisonStrategy); return new ClusterWithLowerAndUpperBoundaries<>(lowerBound, upperBound); } + + private Cluster createCluster(double boundValue, ComparisonStrategy comparisonStrategy) { + return new ClusterWithSingleBoundary<>(new ComparableClusterBoundary<>(boundValue, comparisonStrategy)); + } } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LinearDoubleClusterGroup.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LinearDoubleClusterGroup.java index d7f9d426d29..3b01d97ddf6 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LinearDoubleClusterGroup.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LinearDoubleClusterGroup.java @@ -6,6 +6,7 @@ import java.util.Map; import com.sap.sse.datamining.data.Cluster; import com.sap.sse.datamining.data.ClusterGroup; import com.sap.sse.datamining.impl.data.ClusterWithLowerAndUpperBoundaries; +import com.sap.sse.datamining.impl.data.ClusterWithSingleBoundary; import com.sap.sse.datamining.impl.data.ComparableClusterBoundary; import com.sap.sse.datamining.impl.data.ComparisonStrategy; @@ -19,6 +20,7 @@ public class LinearDoubleClusterGroup implements ClusterGroup { private final boolean hardBounds; private final transient Map> clusterCache; + private final int lastClusterIndex; public LinearDoubleClusterGroup(double lowerBound, double upperBound, double stepSize, boolean hardBounds) { this.lowerBound = lowerBound; @@ -27,35 +29,10 @@ public class LinearDoubleClusterGroup implements ClusterGroup { this.hardBounds = hardBounds; clusterCache = new HashMap<>(); + lastClusterIndex = calculateLastClusterIndex(this.upperBound, this.stepSize); } - @Override - public Cluster getClusterFor(Double valueObject) { - double value = valueObject.doubleValue(); - if (value < lowerBound) { - return hardBounds ? null : getCluster(0); - } - if (value > upperBound) { - return hardBounds ? null : getCluster(getLastClusterIndex()); - } - - if (Math.abs(upperBound - value) < 0.0001) { - return getCluster(getLastClusterIndex()); - } - return getCluster((int) (value / stepSize)); - } - - private Cluster getCluster(int index) { - if (!clusterCache.containsKey(index)) { - ComparableClusterBoundary lowerBound = new ComparableClusterBoundary(this.lowerBound + stepSize * index, ComparisonStrategy.GREATER_EQUALS_THAN); - ComparableClusterBoundary upperBound = new ComparableClusterBoundary(this.lowerBound + stepSize * (index + 1), ComparisonStrategy.LOWER_THAN); - Cluster cluster = new ClusterWithLowerAndUpperBoundaries<>(lowerBound, upperBound); - clusterCache.put(index, cluster); - } - return clusterCache.get(index); - } - - private int getLastClusterIndex() { + private static int calculateLastClusterIndex(double upperBound, double stepSize) { double doubleIndex = upperBound / stepSize; int index = (int) doubleIndex; double fractionalPart = doubleIndex - index; @@ -65,9 +42,69 @@ public class LinearDoubleClusterGroup implements ClusterGroup { return index; } + @Override + public Cluster getClusterFor(Double valueObject) { + double value = valueObject.doubleValue(); + if (value < lowerBound) { + return hardBounds ? null : getCluster(0); + } + if (value > upperBound) { + return hardBounds ? null : getCluster(lastClusterIndex); + } + + if (Math.abs(upperBound - value) < 0.0001) { + return getCluster(lastClusterIndex); + } + return getCluster((int) (value / stepSize)); + } + + private Cluster getCluster(int index) { + if (!clusterCache.containsKey(index)) { + clusterCache.put(index, createCluster(index)); + } + return clusterCache.get(index); + } + + private Cluster createCluster(int index) { + if (index == 0 && !hardBounds) { + return new ClusterWithSingleBoundary<>(createUpperBound(index, ComparisonStrategy.LOWER_THAN)); + } + if (index == lastClusterIndex && !hardBounds) { + return new ClusterWithSingleBoundary<>(createLowerBound(index, ComparisonStrategy.GREATER_EQUALS_THAN)); + } + + ComparisonStrategy upperComparisonStrategy = index == lastClusterIndex ? ComparisonStrategy.LOWER_EQUALS_THAN : ComparisonStrategy.LOWER_THAN; + return new ClusterWithLowerAndUpperBoundaries<>(createLowerBound(index, ComparisonStrategy.GREATER_EQUALS_THAN), + createUpperBound(index, upperComparisonStrategy)); + } + + private ComparableClusterBoundary createLowerBound(int index, ComparisonStrategy comparisonStrategy) { + return new ComparableClusterBoundary(this.lowerBound + stepSize * index, comparisonStrategy); + } + + private ComparableClusterBoundary createUpperBound(int index, ComparisonStrategy comparisonStrategy) { + return new ComparableClusterBoundary(this.lowerBound + stepSize * (index + 1.0), comparisonStrategy); + } + @Override public Class getClusterElementsType() { return Double.class; } + public double getLowerGroupBound() { + return lowerBound; + } + + public double getUpperGroupBound() { + return upperBound; + } + + public double getStepSize() { + return stepSize; + } + + public boolean isHardBounds() { + return hardBounds; + } + } From 5923ac55b252ce73a0edaec4bf95e5ee5a452567 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Sat, 22 Oct 2016 14:29:54 +0200 Subject: [PATCH 31/31] fixed SensorFixStoreAndLoadTest after changing ride height type from double to Distance Change-Id: I1b4864c25732a0d9b5db9275c7e835890ada8f07 --- .../test/impl/SensorFixStoreAndLoadTest.java | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreAndLoadTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreAndLoadTest.java index 0fe9590a085..0d5f03e9a81 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreAndLoadTest.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreAndLoadTest.java @@ -49,9 +49,11 @@ import com.sap.sailing.domain.base.impl.CourseImpl; import com.sap.sailing.domain.base.impl.RaceDefinitionImpl; import com.sap.sailing.domain.base.impl.RegattaImpl; import com.sap.sailing.domain.base.impl.WaypointImpl; +import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.common.impl.DegreeBearingImpl; import com.sap.sailing.domain.common.impl.DegreePosition; import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; +import com.sap.sailing.domain.common.impl.MeterDistance; import com.sap.sailing.domain.common.sensordata.BravoSensorDataMetadata; import com.sap.sailing.domain.common.tracking.DoubleVectorFix; import com.sap.sailing.domain.common.tracking.GPSFixMoving; @@ -95,9 +97,9 @@ public class SensorFixStoreAndLoadTest { private static final long FIX_TIMESTAMP2 = 120; private static final long FIX_TIMESTAMP3 = 210; private static final long AFTER_LAST_FIX = FIX_TIMESTAMP3 + 1; - private static final double FIX_RIDE_HEIGHT = 1337.0; - private static final double FIX_RIDE_HEIGHT2 = 1338.0; - private static final double FIX_RIDE_HEIGHT3 = 1336.0; + private static final Distance FIX_RIDE_HEIGHT = new MeterDistance(1337.0); + private static final Distance FIX_RIDE_HEIGHT2 = new MeterDistance(1338.0); + private static final Distance FIX_RIDE_HEIGHT3 = new MeterDistance(1336.0); private static final double FIX_TEST_VALUE = 12.0; protected final MockSmartphoneImeiServiceFinderFactory serviceFinderFactory = new MockSmartphoneImeiServiceFinderFactory(); protected final DeviceIdentifier device = new SmartphoneImeiIdentifier("a"); @@ -384,20 +386,14 @@ public class SensorFixStoreAndLoadTest { public void testBravoFixIsCorrectlyWrapped() throws InterruptedException { regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp, device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING))); - addBravoFixes(); - FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker(); - trackedRace.attachRaceLog(raceLog); trackedRace.attachRegattaLog(regattaLog); - trackedRace.waitForLoadingToFinish(); - BravoFixTrack bravoFixTrack = trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME); assertEquals(FIX_RIDE_HEIGHT, bravoFixTrack.getFirstFixAtOrAfter(new MillisecondsTimePoint(FIX_TIMESTAMP)).getRideHeight()); - fixLoaderAndTracker.stop(true); } @@ -482,9 +478,9 @@ public class SensorFixStoreAndLoadTest { } private void addBravoFixes() { - store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP, FIX_RIDE_HEIGHT)); - store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP2, FIX_RIDE_HEIGHT2)); - store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP3, FIX_RIDE_HEIGHT3)); + store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP, FIX_RIDE_HEIGHT.getMeters())); + store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP2, FIX_RIDE_HEIGHT2.getMeters())); + store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP3, FIX_RIDE_HEIGHT3.getMeters())); } private FixLoaderAndTracker createFixLoaderAndTracker() {