From 2c064e98552197d9680967ac8aa818c4e81d976e Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 21 Apr 2016 12:59:25 +0200 Subject: [PATCH 1/7] added a parameter "t" to the RaceBoard.html entry point that accepts a time after the start as [[hh:]mm:]ss to position the timer in replay mode Change-Id: Id2e05ba3524e41e00e765c7e689a668093be15d7 --- .../client/place/player/PlayerActivity.java | 2 +- .../sailing/gwt/ui/client/RaceTimePanel.java | 8 +++++-- .../gwt/ui/raceboard/RaceBoardEntryPoint.java | 24 ++++++++++++++++++- .../gwt/ui/raceboard/RaceBoardPanel.java | 2 +- .../raceboard/RaceBoardViewConfiguration.java | 12 ++++++++-- .../home/solutions/SailingAnalyticsNotes.html | 10 ++++++++ 6 files changed, 51 insertions(+), 7 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 beee0dd84ec..7fb1fb78755 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 @@ -79,7 +79,7 @@ public class PlayerActivity extends AbstractActivity { final String defaultMedia = GwtHttpRequestUtils.getStringParameter(RaceBoardViewConfiguration.PARAM_DEFAULT_MEDIA, null /* default */); return new RaceBoardViewConfiguration(activeCompetitorsFilterSetName, showLeaderboard, - showWindChart, showCompetitorsChart, showViewStreamlets, showViewStreamletColors, showViewSimulation, autoSelectMedia, defaultMedia); + showWindChart, showCompetitorsChart, showViewStreamlets, showViewStreamletColors, showViewSimulation, autoSelectMedia, defaultMedia, initialDurationAfterRaceStartInReplay); } private void createErrorView(String errorMessage, Throwable errorReason, AcceptsOneWidget panel) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/RaceTimePanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/RaceTimePanel.java index fcfea781e43..e5446e7be83 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/RaceTimePanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/RaceTimePanel.java @@ -10,6 +10,7 @@ import com.sap.sailing.domain.common.security.SailingPermissionsForRoleProvider; import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil; import com.sap.sailing.gwt.ui.shared.MarkPassingTimesDTO; import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO; +import com.sap.sse.common.Duration; import com.sap.sse.common.Util; import com.sap.sse.gwt.client.player.TimeRangeWithZoomProvider; import com.sap.sse.gwt.client.player.Timer; @@ -43,16 +44,18 @@ public class RaceTimePanel extends TimePanel implements R */ private boolean redrawAllMarkersPendingForMinMaxBeingInitialized; + private final Duration initialTimeAfterRaceStartInReplayMode; public RaceTimePanel(UserService userService, Timer timer, TimeRangeWithZoomProvider timeRangeProvider, StringMessages stringMessages, RaceTimesInfoProvider raceTimesInfoProvider, boolean canReplayWhileLiveIsPossible, boolean isScreenLargeEnoughToOfferChartSupport, - RegattaAndRaceIdentifier selectedRaceIdentifier) { + RegattaAndRaceIdentifier selectedRaceIdentifier, Duration initialTimeAfterRaceStartInReplayMode) { super(timer, timeRangeProvider, stringMessages, canReplayWhileLiveIsPossible, isScreenLargeEnoughToOfferChartSupport); this.userService = userService; this.raceTimesInfoProvider = raceTimesInfoProvider; selectedRace = null; autoAdjustPlayMode = true; selectedRace = selectedRaceIdentifier; + this.initialTimeAfterRaceStartInReplayMode = initialTimeAfterRaceStartInReplayMode; if (!raceTimesInfoProvider.containsRaceIdentifier(selectedRace)) { raceTimesInfoProvider.addRaceIdentifier(selectedRace, true); } @@ -282,7 +285,8 @@ public class RaceTimePanel extends TimePanel implements R case Replay: // set time to start of race if (newRaceTimesInfo.startOfRace != null) { - timer.setTime(newRaceTimesInfo.startOfRace.getTime()); + timer.setTime(newRaceTimesInfo.startOfRace.getTime() + + (initialTimeAfterRaceStartInReplayMode == null ? 0l : initialTimeAfterRaceStartInReplayMode.asMillis())); } break; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java index a8a5f6abb19..ac5de4f02ea 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java @@ -25,6 +25,8 @@ import com.sap.sailing.gwt.ui.client.RaceTimesInfoProvider; import com.sap.sailing.gwt.ui.client.RemoteServiceMappingConstants; import com.sap.sailing.gwt.ui.shared.RaceWithCompetitorsDTO; import com.sap.sailing.gwt.ui.shared.RaceboardDataDTO; +import com.sap.sse.common.Duration; +import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.gwt.client.EntryPointHelper; import com.sap.sse.gwt.client.async.AsyncActionsExecutor; import com.sap.sse.gwt.client.player.Timer; @@ -88,8 +90,10 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint { final boolean autoSelectMedia = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_AUTOSELECT_MEDIA, true); final String defaultMedia = GwtHttpRequestUtils.getStringParameter(RaceBoardViewConfiguration.PARAM_DEFAULT_MEDIA, null /* default*/); final boolean showMapControls = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_MAPCONTROLS, true /* default*/); + final Duration initialDurationAfterRaceStartInReplay = parseDuration(GwtHttpRequestUtils.getStringParameter(RaceBoardViewConfiguration.PARAM_TIME_AFTER_RACE_START_AS_HOURS_COLON_MILLIS_COLON_SECONDS, null /* default*/)); raceboardViewConfig = new RaceBoardViewConfiguration(activeCompetitorsFilterSetName, showLeaderboard, - showWindChart, showCompetitorsChart, showViewStreamlets, showViewStreamletColors, showViewSimulation, autoSelectMedia, defaultMedia); + showWindChart, showCompetitorsChart, showViewStreamlets, showViewStreamletColors, showViewSimulation, autoSelectMedia, defaultMedia, + initialDurationAfterRaceStartInReplay); sailingService.getRaceboardData(regattaName, raceName, leaderboardName, leaderboardGroupName, eventId, new AsyncCallback() { @Override public void onSuccess(RaceboardDataDTO result) { @@ -107,6 +111,24 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint { }); } + /** + * Understands [hh:[mm:]]ss and parses into a {@link Duration}. If {@code durationAsString} is {@code null} then + * so is the result. + */ + private Duration parseDuration(String durationAsString) { + final Duration result; + if (durationAsString == null) { + result = null; + } else { + long seconds = 0; + for (final String hhmmss : durationAsString.split(":")) { + seconds = 60*seconds + Long.valueOf(hhmmss); + } + result = new MillisecondsDurationImpl(1000l * seconds); + } + return result; + } + private void createErrorPage(String message) { final DockLayoutPanel vp = new DockLayoutPanel(Unit.PX); LogoAndTitlePanel logoAndTitlePanel = new LogoAndTitlePanel(getStringMessages(), this, getUserService()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java index 60f2fa80031..0ea4c8f0b8c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java @@ -234,7 +234,7 @@ public class RaceBoardPanel extends SimplePanel implements LeaderboardUpdateList } } timePanel = new RaceTimePanel(userService, timer, timeRangeWithZoomModel, stringMessages, raceTimesInfoProvider, - false, isScreenLargeEnoughToOfferChartSupport, selectedRaceIdentifier); + false, isScreenLargeEnoughToOfferChartSupport, selectedRaceIdentifier, getConfiguration().getInitialDurationAfterRaceStartInReplay()); timeRangeWithZoomModel.addTimeZoomChangeListener(timePanel); raceTimesInfoProvider.addRaceTimesInfoProviderListener(timePanel); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardViewConfiguration.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardViewConfiguration.java index 3d49c69dfa5..6ce85822512 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardViewConfiguration.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardViewConfiguration.java @@ -1,5 +1,7 @@ package com.sap.sailing.gwt.ui.raceboard; +import com.sap.sse.common.Duration; + /** * Represents the parameters for configuring the raceboard view * @author Frank @@ -15,6 +17,7 @@ public class RaceBoardViewConfiguration { private final boolean showViewStreamlets; private final boolean showViewStreamletColors; private final boolean showViewSimulation; + private final Duration initialDurationAfterRaceStartInReplay; public static final String PARAM_VIEW_MODE = "viewMode"; public static final String PARAM_VIEW_SHOW_LEADERBOARD = "viewShowLeaderboard"; @@ -29,16 +32,17 @@ public class RaceBoardViewConfiguration { public static final String PARAM_CAN_REPLAY_DURING_LIVE_RACES = "canReplayDuringLiveRaces"; public static final String PARAM_AUTOSELECT_MEDIA = "autoSelectMedia"; public static final String PARAM_DEFAULT_MEDIA = "defaultMedia"; + public static final String PARAM_TIME_AFTER_RACE_START_AS_HOURS_COLON_MILLIS_COLON_SECONDS = "t"; public RaceBoardViewConfiguration() { this(/* activeCompetitorsFilterSetName */ null, /* showLeaderboard */ true, /* showWindChart */ false, /* showCompetitorsChart */ false, /* showViewStreamlets */ false, /* showViewStreamletColors */ false, /* showViewSimulation */ false, - /* autoSelectMedia */false, null); + /* autoSelectMedia */false, null, /* initialDurationAfterRaceStartInReplay */ null); } public RaceBoardViewConfiguration(String activeCompetitorsFilterSetName, boolean showLeaderboard, boolean showWindChart, boolean showCompetitorsChart, boolean showViewStreamlets, boolean showViewStreamletColors, boolean showViewSimulation, - boolean autoSelectMedia, String defaultMedia) { + boolean autoSelectMedia, String defaultMedia, Duration initialDurationAfterRaceStartInReplay) { this.activeCompetitorsFilterSetName = activeCompetitorsFilterSetName; this.showLeaderboard = showLeaderboard; this.showWindChart = showWindChart; @@ -48,6 +52,7 @@ public class RaceBoardViewConfiguration { this.showViewSimulation = showViewSimulation; this.autoSelectMedia = autoSelectMedia; this.defaultMedia = defaultMedia; + this.initialDurationAfterRaceStartInReplay = initialDurationAfterRaceStartInReplay; } public boolean isShowLeaderboard() { @@ -86,4 +91,7 @@ public class RaceBoardViewConfiguration { return defaultMedia; } + public Duration getInitialDurationAfterRaceStartInReplay() { + return initialDurationAfterRaceStartInReplay; + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/SailingAnalyticsNotes.html b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/SailingAnalyticsNotes.html index 197c0c519b1..48dfa3eafcc 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/SailingAnalyticsNotes.html +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/SailingAnalyticsNotes.html @@ -22,6 +22,16 @@ +
April 2016
+
    +
  • The /gwt/RaceBoard.html entry point now accepts an optional parameter "t" in the form + [[hh:]mm:]ss, for example t=12:34 to place the timer so much after the race start + if the viewer comes up in Replay mode. You may also use just seconds, as in t=1234 which + makes specifying a time before the start somewhat easier (t=-123 instead of + t=-02:-03). +
  • +
+
January 2016
  • Show maneuver markers on the race board by default From bbc94b82dcf855a1060b0277bd86a7b99d65d5fe Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 21 Apr 2016 13:12:39 +0200 Subject: [PATCH 2/7] fixing PlayerActivity after introducing initialDurationAfterRaceStartInReplay Change-Id: Iaf34f7d5098c731ffa012b8b4f0a36077b65a908 --- .../gwt/autoplay/client/place/player/PlayerActivity.java | 4 ++++ .../com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) 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 7fb1fb78755..746e4bd55da 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 @@ -8,8 +8,10 @@ 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.google.gwt.user.client.ui.RootLayoutPanel; +import com.sap.sailing.gwt.ui.raceboard.RaceBoardEntryPoint; import com.sap.sailing.gwt.ui.raceboard.RaceBoardViewConfiguration; import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sse.common.Duration; import com.sap.sse.gwt.client.mvp.ErrorView; import com.sap.sse.gwt.client.useragent.UserAgentDetails; import com.sap.sse.gwt.shared.GwtHttpRequestUtils; @@ -77,6 +79,8 @@ public class PlayerActivity extends AbstractActivity { RaceBoardViewConfiguration.PARAM_VIEW_SHOW_COMPETITORSCHART, false /* default */); String activeCompetitorsFilterSetName = GwtHttpRequestUtils.getStringParameter(RaceBoardViewConfiguration.PARAM_VIEW_COMPETITOR_FILTER, null /* default*/); final String defaultMedia = GwtHttpRequestUtils.getStringParameter(RaceBoardViewConfiguration.PARAM_DEFAULT_MEDIA, null /* default */); + final Duration initialDurationAfterRaceStartInReplay = RaceBoardEntryPoint.parseDuration(GwtHttpRequestUtils.getStringParameter( + RaceBoardViewConfiguration.PARAM_TIME_AFTER_RACE_START_AS_HOURS_COLON_MILLIS_COLON_SECONDS, null /* default */)); return new RaceBoardViewConfiguration(activeCompetitorsFilterSetName, showLeaderboard, showWindChart, showCompetitorsChart, showViewStreamlets, showViewStreamletColors, showViewSimulation, autoSelectMedia, defaultMedia, initialDurationAfterRaceStartInReplay); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java index ac5de4f02ea..1b6f153f552 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java @@ -115,7 +115,7 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint { * Understands [hh:[mm:]]ss and parses into a {@link Duration}. If {@code durationAsString} is {@code null} then * so is the result. */ - private Duration parseDuration(String durationAsString) { + public static Duration parseDuration(String durationAsString) { final Duration result; if (durationAsString == null) { result = null; From 5f5a3c460eb247d3ac788b1d0e75a3514d64d1aa Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 22 Apr 2016 16:47:39 +0200 Subject: [PATCH 3/7] introduced CourseDesignerMode field on RaceLogCourseDesignChangedEvent and field isWaypointSequenceValid on CourseDesignerMode; this is to solve bug 3608 because course designs coming from the ByName course editor will no longer be used to update a TrackedRace's course. Change-Id: I8a1aa432f931838902c546a2365b68a8ca59b72e --- .../domain/common/CourseDesignerMode.java | 24 +++++++++++---- .../impl/DomainObjectFactoryImpl.java | 5 +++- .../domain/persistence/impl/FieldNames.java | 2 +- .../impl/MongoObjectFactoryImpl.java | 2 ++ .../impl/RaceLogRaceTracker.java | 4 +-- .../impl/RaceLogTrackingAdapterImpl.java | 5 ++-- .../racelog/state/test/RaceStateTest.java | 3 +- .../race/RaceLogCourseDesignChangedEvent.java | 3 ++ .../impl/LastPublishedCourseDesignFinder.java | 29 +++++++++++++++++-- .../RaceLogCourseDesignChangedEventImpl.java | 18 +++++++++--- .../abstractlog/race/state/RaceState.java | 9 +++++- .../race/state/impl/RaceStateImpl.java | 5 ++-- .../state/impl/ReadonlyRaceStateImpl.java | 2 +- .../domain/base/impl/AbstractRaceColumn.java | 2 +- .../impl/DynamicTrackedRaceLogListener.java | 2 +- .../gwt/ui/server/SailingServiceImpl.java | 14 +++++---- ...ingAndRetrievingRaceLogInLeaderboards.java | 3 +- ...tStoringAndRetrievingRaceLogInRegatta.java | 3 +- ...gCourseDesignChangedEventDeserializer.java | 6 ++-- ...LogCourseDesignChangedEventSerializer.java | 4 +-- ...ourseDesignChangedEventSerializerTest.java | 4 ++- .../racelog/RaceLogEventSerializerTest.java | 3 +- .../test/RaceLogReplicationTest.java | 9 +++--- .../raceinfo/CourseFragmentMarks.java | 3 +- .../raceinfo/CourseFragmentName.java | 3 +- 25 files changed, 122 insertions(+), 45 deletions(-) diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/CourseDesignerMode.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/CourseDesignerMode.java index 627266e2e18..32f66797e7e 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/CourseDesignerMode.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/CourseDesignerMode.java @@ -9,15 +9,23 @@ import java.util.List; * When modifying these values also check res/preferences.xml of racecommittee.app! */ public enum CourseDesignerMode { - UNKNOWN("Unknown"), - BY_NAME("By-Name Course Designer"), // O2, O3, I2,... - BY_MAP("By-Map Course Designer"), // Map-based Course Designer - BY_MARKS("By-Marks Course Designer"); // ESS + UNKNOWN("Unknown", /* waypointSequenceValid */ false), + BY_NAME("By-Name Course Designer", /* waypointSequenceValid */ false), // O2, O3, I2,... + BY_MAP("By-Map Course Designer", /* waypointSequenceValid */ true), // Map-based Course Designer + BY_MARKS("By-Marks Course Designer", /* waypointSequenceValid */ true), // ESS + ADMIN_CONSOLE("Administration Console", /* waypointSequenceValid */ true); - private String displayName; + private final String displayName; + + /** + * Some course designers may only be able to tell, say, a name for the new course but not + * necessarily a valid waypoint sequence. This flag tells. + */ + private final boolean waypointSequenceValid; - private CourseDesignerMode(String displayName) { + private CourseDesignerMode(String displayName, boolean waypointSequenceValid) { this.displayName = displayName; + this.waypointSequenceValid = waypointSequenceValid; } @Override @@ -25,6 +33,10 @@ public enum CourseDesignerMode { return displayName; } + public boolean isWaypointSequenceValid() { + return waypointSequenceValid; + } + public static CourseDesignerMode[] validValues() { List validValues = new ArrayList(); for (CourseDesignerMode type : values()) { diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index 9eb8f687b6b..2680b9b4441 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -143,6 +143,7 @@ import com.sap.sailing.domain.base.impl.SailingServerConfigurationImpl; import com.sap.sailing.domain.base.impl.SeriesImpl; import com.sap.sailing.domain.base.impl.VenueImpl; import com.sap.sailing.domain.base.impl.WaypointImpl; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.MarkType; import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sailing.domain.common.PassingInstruction; @@ -1498,7 +1499,9 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { private RaceLogCourseDesignChangedEvent loadRaceLogCourseDesignChangedEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { String courseName = (String) dbObject.get(FieldNames.RACE_LOG_COURSE_DESIGN_NAME.name()); CourseBase courseData = loadCourseData((BasicDBList) dbObject.get(FieldNames.RACE_LOG_COURSE_DESIGN.name()), courseName); - return new RaceLogCourseDesignChangedEventImpl(createdAt, logicalTimePoint, author, id, passId, courseData); + final String courseDesignerModeName = (String) dbObject.get(FieldNames.RACE_LOG_COURSE_DESIGNER_MODE.name()); + final CourseDesignerMode courseDesignerMode = courseDesignerModeName == null ? null : CourseDesignerMode.valueOf(courseDesignerModeName); + return new RaceLogCourseDesignChangedEventImpl(createdAt, logicalTimePoint, author, id, passId, courseData, courseDesignerMode); } private RaceLogCourseAreaChangedEvent loadRaceLogCourseAreaChangedEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, DBObject dbObject) { diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java index 1763fe75957..ab6560670e6 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java @@ -88,7 +88,7 @@ public enum FieldNames { // race log RACE_LOG_IDENTIFIER, RACE_LOG_EVENT, RACE_LOG_EVENT_PASS_ID, RACE_LOG_EVENT_ID, RACE_LOG_EVENT_CREATED_AT, RACE_LOG_EVENT_AUTHOR_NAME, RACE_LOG_EVENT_AUTHOR_PRIORITY, RACE_LOG_EVENT_INVOLVED_BOATS, RACE_LOG_EVENT_FLAG_UPPER, RACE_LOG_EVENT_FLAG_LOWER, RACE_LOG_EVENT_FLAG_DISPLAYED, - RACE_LOG_EVENT_START_TIME, RACE_LOG_EVENT_CLASS, RACE_LOG_EVENT_NEXT_STATUS, RACE_LOG_COURSE_DESIGN, WAYPOINT_ID, WAYPOINT_NAME, + RACE_LOG_EVENT_START_TIME, RACE_LOG_EVENT_CLASS, RACE_LOG_EVENT_NEXT_STATUS, RACE_LOG_COURSE_DESIGN, RACE_LOG_COURSE_DESIGNER_MODE, WAYPOINT_ID, WAYPOINT_NAME, WAYPOINT_PASSINGINSTRUCTIONS, CONTROLPOINT, CONTROLPOINT_CLASS, MARK_ID, MARK_COLOR, MARK_NAME, MARK_PATTERN, MARK_SHAPE, MARK_TYPE, CONTROLPOINT_VALUE, CONTROLPOINTWITHTWOMARKS_ID, CONTROLPOINTWITHTWOMARKS_NAME, CONTROLPOINTWITHTWOMARKS_LEFT, CONTROLPOINTWITHTWOMARKS_RIGHT, RACE_LOG_POSITIONED_COMPETITORS, RACE_LOG_PATHFINDER_ID, RACE_LOG_GATE_LINE_OPENING_TIME, RACE_LOG_GOLF_DOWN_TIME, RACE_LOG_START_PROCEDURE_TYPE, diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java index 8377d398eff..9942e04dbd7 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java @@ -1116,6 +1116,8 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory { storeRaceLogEventProperties(courseDesignChangedEvent, result); result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogCourseDesignChangedEvent.class.getSimpleName()); result.put(FieldNames.RACE_LOG_COURSE_DESIGN_NAME.name(), courseDesignChangedEvent.getCourseDesign().getName()); + result.put(FieldNames.RACE_LOG_COURSE_DESIGNER_MODE.name(), + courseDesignChangedEvent.getCourseDesignerMode() == null ? null : courseDesignChangedEvent.getCourseDesignerMode().name()); result.put(FieldNames.RACE_LOG_COURSE_DESIGN.name(), storeCourseBase(courseDesignChangedEvent.getCourseDesign())); return result; } diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java index 5e9ca597b04..cab79b3e678 100755 --- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java @@ -436,7 +436,7 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener { private void onCourseDesignChangedEvent(RaceLogCourseDesignChangedEvent event) { if (trackedRace != null) { - CourseBase base = new LastPublishedCourseDesignFinder(params.getRaceLog()).analyze(); + CourseBase base = new LastPublishedCourseDesignFinder(params.getRaceLog(), /* onlyCoursesWithValidWaypointList */ true).analyze(); List> update = new ArrayList<>(); for (Waypoint waypoint : base.getWaypoints()) { update.add(new Util.Pair<>(waypoint.getControlPoint(), waypoint.getPassingInstructions())); @@ -462,7 +462,7 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener { } BoatClass boatClass = denoteEvent.getBoatClass(); String raceName = denoteEvent.getRaceName(); - CourseBase courseBase = new LastPublishedCourseDesignFinder(raceLog).analyze(); + CourseBase courseBase = new LastPublishedCourseDesignFinder(raceLog, /* onlyCoursesWithValidWaypointList */ true).analyze(); if (courseBase == null) { courseBase = new CourseDataImpl("Default course for " + raceName); logger.log(Level.FINE, "Using empty course in creation of race " + raceName); diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingAdapterImpl.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingAdapterImpl.java index d11b48e86cc..97368304af2 100755 --- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingAdapterImpl.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingAdapterImpl.java @@ -47,6 +47,7 @@ import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.SharedDomainFactory; import com.sap.sailing.domain.base.Waypoint; import com.sap.sailing.domain.base.impl.CourseDataImpl; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.RegattaIdentifier; import com.sap.sailing.domain.common.abstractlog.NotRevokableException; import com.sap.sailing.domain.common.racelog.tracking.CompetitorRegistrationOnRaceLogDisabledException; @@ -194,7 +195,7 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter { @Override public void copyCourse(RaceLog fromRaceLog, Set toRaceLogs, SharedDomainFactory baseDomainFactory, RacingEventService service) { - CourseBase course = new LastPublishedCourseDesignFinder(fromRaceLog).analyze(); + CourseBase course = new LastPublishedCourseDesignFinder(fromRaceLog, /* onlyCoursesWithValidWaypointList */ true).analyze(); final Set marks = new HashSet<>(); if (course != null) { course.getWaypoints().forEach(wp -> Util.addAll(wp.getMarks(), marks)); @@ -212,7 +213,7 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter { int passId = toRaceLog.getCurrentPassId(); RaceLogEvent newCourseEvent = new RaceLogCourseDesignChangedEventImpl(now, - service.getServerAuthor(), passId, newCourse); + service.getServerAuthor(), passId, newCourse, CourseDesignerMode.ADMIN_CONSOLE); toRaceLog.add(newCourseEvent); } diff --git a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/state/test/RaceStateTest.java b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/state/test/RaceStateTest.java index 6d53331d754..a1d5062a69a 100644 --- a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/state/test/RaceStateTest.java +++ b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/state/test/RaceStateTest.java @@ -37,6 +37,7 @@ import com.sap.sailing.domain.base.configuration.RegattaConfiguration; import com.sap.sailing.domain.base.configuration.impl.EmptyRegattaConfiguration; import com.sap.sailing.domain.base.configuration.impl.RegattaConfigurationImpl; import com.sap.sailing.domain.base.configuration.procedures.ESSConfiguration; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.racelog.Flags; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; import com.sap.sailing.domain.common.racelog.RacingProcedureType; @@ -177,7 +178,7 @@ public class RaceStateTest { state.forceNewStartTime(nowMock, new MillisecondsTimePoint(1)); Thread.sleep(100); state.setFinishedTime(new MillisecondsTimePoint(10)); - state.setCourseDesign(nowMock, mock(CourseBase.class)); + state.setCourseDesign(nowMock, mock(CourseBase.class), CourseDesignerMode.ADMIN_CONSOLE); state.setAdvancePass(mock(TimePoint.class)); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogCourseDesignChangedEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogCourseDesignChangedEvent.java index 97592723862..c63555fba5d 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogCourseDesignChangedEvent.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogCourseDesignChangedEvent.java @@ -1,9 +1,12 @@ package com.sap.sailing.domain.abstractlog.race; import com.sap.sailing.domain.base.CourseBase; +import com.sap.sailing.domain.common.CourseDesignerMode; public interface RaceLogCourseDesignChangedEvent extends RaceLogEvent { CourseBase getCourseDesign(); + + CourseDesignerMode getCourseDesignerMode(); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/LastPublishedCourseDesignFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/LastPublishedCourseDesignFinder.java index d5101afd45d..ec92eaa3d7c 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/LastPublishedCourseDesignFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/LastPublishedCourseDesignFinder.java @@ -4,11 +4,33 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; import com.sap.sailing.domain.base.CourseBase; +import com.sap.sailing.domain.common.CourseDesignerMode; +/** + * A course design can be defined in the {@link RaceLog} using a {@link RaceLogCourseDesignChangedEvent}. These + * events may carry information about the course designer that was used to create the course. Not all of them + * support defining the waypoint sequence that sets the course. See {@link RaceLogCourseDesignChangedEvent#getCourseDesignerMode()} + * and {@link CourseDesignerMode#isWaypointSequenceValid()}. Callers can tell whether they want to obtain {@link CourseBase} + * objects regardless of whether their waypoint sequence is valid or not. + * + * @author Axel Uhl (d043530) + * + */ public class LastPublishedCourseDesignFinder extends RaceLogAnalyzer { - public LastPublishedCourseDesignFinder(RaceLog raceLog) { + private final boolean onlyCoursesWithValidWaypointList; + + /** + * @param onlyCoursesWithValidWaypointList + * if {@code true}, only {@link RaceLogCourseDesignChangedEvent} objects will be considered whose + * {@link RaceLogCourseDesignChangedEvent#getCourseDesignerMode() course designer mode} + * {@link CourseDesignerMode#isWaypointSequenceValid() guarantees} that the waypoint list is valid and + * shall be applied to a race; otherwise, all other {@link RaceLogCourseDesignChangedEvent} as considered + * as well. + */ + public LastPublishedCourseDesignFinder(RaceLog raceLog, boolean onlyCoursesWithValidWaypointList) { super(raceLog); + this.onlyCoursesWithValidWaypointList = onlyCoursesWithValidWaypointList; } @Override @@ -16,7 +38,10 @@ public class LastPublishedCourseDesignFinder extends RaceLogAnalyzer for (RaceLogEvent event : getAllEventsDescending()) { if (event instanceof RaceLogCourseDesignChangedEvent) { RaceLogCourseDesignChangedEvent courseDesignEvent = (RaceLogCourseDesignChangedEvent) event; - return courseDesignEvent.getCourseDesign(); + if (!onlyCoursesWithValidWaypointList || (courseDesignEvent.getCourseDesignerMode() != null && + courseDesignEvent.getCourseDesignerMode().isWaypointSequenceValid())) { + return courseDesignEvent.getCourseDesign(); + } } } return null; diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/RaceLogCourseDesignChangedEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/RaceLogCourseDesignChangedEventImpl.java index c295cf8d891..11900dd831d 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/RaceLogCourseDesignChangedEventImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/RaceLogCourseDesignChangedEventImpl.java @@ -6,23 +6,27 @@ import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor; import com.sap.sailing.domain.base.CourseBase; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sse.common.TimePoint; public class RaceLogCourseDesignChangedEventImpl extends RaceLogEventImpl implements RaceLogCourseDesignChangedEvent { private static final long serialVersionUID = 1565936170747420547L; private final CourseBase courseDesign; + + private final CourseDesignerMode courseDesignerMode; public RaceLogCourseDesignChangedEventImpl(TimePoint createdAt, TimePoint pTimePoint, AbstractLogEventAuthor author, Serializable pId, int pPassId, - CourseBase courseDesign) { + CourseBase courseDesign, CourseDesignerMode courseDesignerMode) { super(createdAt, pTimePoint, author, pId, pPassId); this.courseDesign = courseDesign; + this.courseDesignerMode = courseDesignerMode; } public RaceLogCourseDesignChangedEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author, int pPassId, - CourseBase courseDesign) { - this(now(), logicalTimePoint, author, randId(), pPassId, courseDesign); + CourseBase courseDesign, CourseDesignerMode courseDesignerMode) { + this(now(), logicalTimePoint, author, randId(), pPassId, courseDesign, courseDesignerMode); } @Override @@ -35,8 +39,14 @@ public class RaceLogCourseDesignChangedEventImpl extends RaceLogEventImpl implem return courseDesign; } + @Override + public CourseDesignerMode getCourseDesignerMode() { + return courseDesignerMode; + } + @Override public String getShortInfo() { return "courseDesign=" + courseDesign != null ? courseDesign.getName() : "null"; } -} + +} \ No newline at end of file diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/RaceState.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/RaceState.java index 38c0cfd5e67..0b35b4d0b6f 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/RaceState.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/RaceState.java @@ -13,6 +13,7 @@ import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProce import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedurePrerequisite.Resolver; import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.impl.RacingProcedurePrerequisiteAutoResolver; import com.sap.sailing.domain.base.CourseBase; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.Wind; import com.sap.sailing.domain.common.racelog.Flags; import com.sap.sailing.domain.common.racelog.RacingProcedureType; @@ -172,8 +173,14 @@ public interface RaceState extends ReadonlyRaceState { /** * Sets a new active course design. + * + * @param courseDesignerMode + * the type of course designer through which the course was created; this decides about whether the + * waypoint specification will be considered at all. For example, the "By Marks" course designer does not + * produce a valid waypoints list which therefore must be ignored instead of using it to update a + * TrackedRace's course. */ - void setCourseDesign(TimePoint now, CourseBase courseDesign); + void setCourseDesign(TimePoint now, CourseBase courseDesign, CourseDesignerMode courseDesignerMode); /** * Enters a new wind fix for this race. diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java index 96ec8bb31cb..0200a3480d5 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java @@ -37,6 +37,7 @@ import com.sap.sailing.domain.base.CourseBase; import com.sap.sailing.domain.base.configuration.ConfigurationLoader; import com.sap.sailing.domain.base.configuration.RegattaConfiguration; import com.sap.sailing.domain.base.configuration.impl.EmptyRegattaConfiguration; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.Wind; import com.sap.sailing.domain.common.abstractlog.NotRevokableException; import com.sap.sailing.domain.common.racelog.Flags; @@ -201,8 +202,8 @@ public class RaceStateImpl extends ReadonlyRaceStateImpl implements RaceState { } @Override - public void setCourseDesign(TimePoint timePoint, CourseBase courseDesign) { - raceLog.add(new RaceLogCourseDesignChangedEventImpl(timePoint, author, raceLog.getCurrentPassId(), courseDesign)); + public void setCourseDesign(TimePoint timePoint, CourseBase courseDesign, CourseDesignerMode courseDesignerMode) { + raceLog.add(new RaceLogCourseDesignChangedEventImpl(timePoint, author, raceLog.getCurrentPassId(), courseDesign, courseDesignerMode)); } @Override diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/ReadonlyRaceStateImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/ReadonlyRaceStateImpl.java index ee24b42e606..73dd9f713bb 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/ReadonlyRaceStateImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/ReadonlyRaceStateImpl.java @@ -186,7 +186,7 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL this.protestTimeAnalyzer = new ProtestStartTimeFinder(raceLog); this.finishPositioningListAnalyzer = new FinishPositioningListFinder(raceLog); this.confirmedFinishPositioningListAnalyzer = new ConfirmedFinishPositioningListFinder(raceLog); - this.courseDesignerAnalyzer = new LastPublishedCourseDesignFinder(raceLog); + this.courseDesignerAnalyzer = new LastPublishedCourseDesignFinder(raceLog, /* onlyCoursesWithValidWaypointList */ false); this.lastWindFixAnalyzer = new LastWindFixFinder(raceLog); this.raceStateToObserveListener = new BaseRaceStateChangedListener() { diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java index 698922f3a08..3f5174a7f4d 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java @@ -339,7 +339,7 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem } } else { // if no tracked race is found, use marks from race course if present in racelog - LastPublishedCourseDesignFinder courseDesginFinder = new LastPublishedCourseDesignFinder(getRaceLog(fleet)); + LastPublishedCourseDesignFinder courseDesginFinder = new LastPublishedCourseDesignFinder(getRaceLog(fleet), /* onlyCoursesWithValidWaypointList */ true); final CourseBase courseBase = courseDesginFinder.analyze(); if (courseBase != null) { courseBase.getWaypoints().forEach((waypoint) -> Util.addAll(waypoint.getMarks(), result)); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java index cc546138856..1886af12f0d 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java @@ -75,7 +75,7 @@ public class DynamicTrackedRaceLogListener extends BaseRaceLogEventVisitor { } private LastPublishedCourseDesignFinder createCourseDesignFinder(RaceLog raceLog) { - return new LastPublishedCourseDesignFinder(raceLog); + return new LastPublishedCourseDesignFinder(raceLog, /* onlyCoursesWithValidWaypointList */ false); // we also want by-name courses to forward, e.g., to TracTrac } private AbortingFlagFinder createAbortingFlagFinder(RaceLog raceLog) { 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 4f1bf6e465b..5005c9466e8 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 @@ -144,6 +144,7 @@ import com.sap.sailing.domain.base.impl.SailingServerConfigurationImpl; import com.sap.sailing.domain.base.impl.SeriesImpl; import com.sap.sailing.domain.base.impl.TeamImpl; import com.sap.sailing.domain.common.Bearing; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.DataImportProgress; import com.sap.sailing.domain.common.DetailType; import com.sap.sailing.domain.common.Distance; @@ -5229,10 +5230,10 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S List> courseDTO) throws NotFoundException { RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); String courseName = "Course of " + raceColumnName; - if(!LeaderboardNameConstants.DEFAULT_FLEET_NAME.equals(fleetName)) { - courseName += "- " + fleetName; + if (!LeaderboardNameConstants.DEFAULT_FLEET_NAME.equals(fleetName)) { + courseName += " - " + fleetName; } - CourseBase lastPublishedCourse = new LastPublishedCourseDesignFinder(raceLog).analyze(); + CourseBase lastPublishedCourse = new LastPublishedCourseDesignFinder(raceLog, /* onlyCoursesWithValidWaypointList */ false).analyze(); if (lastPublishedCourse == null) { lastPublishedCourse = new CourseDataImpl(courseName); } @@ -5250,7 +5251,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } RaceLogEvent event = new RaceLogCourseDesignChangedEventImpl(MillisecondsTimePoint.now(), - getService().getServerAuthor(), raceLog.getCurrentPassId(), course); + getService().getServerAuthor(), raceLog.getCurrentPassId(), course, CourseDesignerMode.ADMIN_CONSOLE); raceLog.add(event); } @@ -5299,7 +5300,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override public RaceCourseDTO getLastCourseDefinitionInRaceLog(final String leaderboardName, String raceColumnName, String fleetName) throws NotFoundException { final RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); - CourseBase lastPublishedCourse = new LastPublishedCourseDesignFinder(raceLog).analyze(); + // only look for course definitions that really define waypoints; ignore by-name course updates + CourseBase lastPublishedCourse = new LastPublishedCourseDesignFinder(raceLog, /* onlyCoursesWithValidWaypointList */ true).analyze(); if (lastPublishedCourse == null) { lastPublishedCourse = new CourseDataImpl(""); } @@ -6056,7 +6058,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S for (Fleet fleet : raceColumn.getFleets()) { RaceLog raceLog = raceColumn.getRaceLog(fleet); if (raceLog != raceLogToIgnore) { - LastPublishedCourseDesignFinder finder = new LastPublishedCourseDesignFinder(raceLog); + LastPublishedCourseDesignFinder finder = new LastPublishedCourseDesignFinder(raceLog, /* onlyCoursesWithValidWaypointList */ true); CourseBase course = finder.analyze(); if (course != null) { for (Waypoint waypoint : course.getWaypoints()) { diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInLeaderboards.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInLeaderboards.java index 8bd6033f7e4..519b83672b6 100644 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInLeaderboards.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInLeaderboards.java @@ -62,6 +62,7 @@ import com.sap.sailing.domain.base.CourseBase; import com.sap.sailing.domain.base.DomainFactory; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.RaceColumn; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sailing.domain.common.Wind; import com.sap.sailing.domain.common.racelog.Flags; @@ -514,7 +515,7 @@ public class TestStoringAndRetrievingRaceLogInLeaderboards extends RaceLogMongoD @Test public void testStoreAndRetrieveSimpleLeaderboardWithRaceLogCourseDesignChangedEvent() { CourseBase course = createCourseBase(); - RaceLogCourseDesignChangedEvent event = new RaceLogCourseDesignChangedEventImpl(now, author, 0, course); + RaceLogCourseDesignChangedEvent event = new RaceLogCourseDesignChangedEventImpl(now, author, 0, course, CourseDesignerMode.ADMIN_CONSOLE); addAndStoreRaceLogEvent(leaderboard, raceColumnName, event); diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInRegatta.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInRegatta.java index 796528a1c40..8d7d476a755 100644 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInRegatta.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingRaceLogInRegatta.java @@ -53,6 +53,7 @@ import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Series; import com.sap.sailing.domain.base.impl.FleetImpl; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sailing.domain.common.Wind; import com.sap.sailing.domain.common.racelog.Flags; @@ -387,7 +388,7 @@ public class TestStoringAndRetrievingRaceLogInRegatta extends AbstractTestStorin @Test public void testStoreAndRetrieveRegattaWithRaceLogCourseDesignChangedEvent() { CourseBase course = createCourseBase(); - RaceLogCourseDesignChangedEvent event = new RaceLogCourseDesignChangedEventImpl(now, author, 0, course); + RaceLogCourseDesignChangedEvent event = new RaceLogCourseDesignChangedEventImpl(now, author, 0, course, CourseDesignerMode.ADMIN_CONSOLE); addAndStoreRaceLogEvent(regatta, raceColumnName, event); diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogCourseDesignChangedEventDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogCourseDesignChangedEventDeserializer.java index 2f61f1af5be..49b536a7338 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogCourseDesignChangedEventDeserializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogCourseDesignChangedEventDeserializer.java @@ -10,6 +10,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogCourseDesignChangedEventImpl; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseBase; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; import com.sap.sailing.server.gateway.deserialization.coursedata.impl.CourseBaseDeserializer; @@ -31,8 +32,9 @@ public class RaceLogCourseDesignChangedEventDeserializer extends BaseRaceLogEven JSONObject jsonCourseDesign = (JSONObject) object.get(RaceLogCourseDesignChangedEventSerializer.FIELD_COURSE_DESIGN); CourseBase courseData = courseDataDeserializer.deserialize(jsonCourseDesign); - - return new RaceLogCourseDesignChangedEventImpl(createdAt, timePoint, author, id, passId, courseData); + final String courseDesignerModeName = (String) object.get(RaceLogCourseDesignChangedEventSerializer.FIELD_COURSE_DESIGNER_MODE); + return new RaceLogCourseDesignChangedEventImpl(createdAt, timePoint, author, id, passId, courseData, + courseDesignerModeName == null ? null : CourseDesignerMode.valueOf(courseDesignerModeName)); } } diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogCourseDesignChangedEventSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogCourseDesignChangedEventSerializer.java index 9b104f509c1..1c62b0ff6d3 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogCourseDesignChangedEventSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogCourseDesignChangedEventSerializer.java @@ -12,6 +12,7 @@ public class RaceLogCourseDesignChangedEventSerializer extends BaseRaceLogEventS public static final String VALUE_CLASS = RaceLogCourseDesignChangedEvent.class.getSimpleName(); public static final String FIELD_COURSE_DESIGN = "courseDesign"; + public static final String FIELD_COURSE_DESIGNER_MODE = "courseDesignerMode"; private final JsonSerializer courseBaseSerializer; @@ -30,10 +31,9 @@ public class RaceLogCourseDesignChangedEventSerializer extends BaseRaceLogEventS @Override public JSONObject serialize(RaceLogEvent object) { RaceLogCourseDesignChangedEvent courseChangedEvent = (RaceLogCourseDesignChangedEvent) object; - JSONObject result = super.serialize(courseChangedEvent); result.put(FIELD_COURSE_DESIGN, courseBaseSerializer.serialize(courseChangedEvent.getCourseDesign())); - + result.put(FIELD_COURSE_DESIGNER_MODE, courseChangedEvent.getCourseDesignerMode() == null ? null : courseChangedEvent.getCourseDesignerMode().name()); return result; } diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogCourseDesignChangedEventSerializerTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogCourseDesignChangedEventSerializerTest.java index aa606905231..7a05e55e1ba 100644 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogCourseDesignChangedEventSerializerTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogCourseDesignChangedEventSerializerTest.java @@ -23,6 +23,7 @@ import com.sap.sailing.domain.base.impl.ControlPointWithTwoMarksImpl; import com.sap.sailing.domain.base.impl.CourseDataImpl; import com.sap.sailing.domain.base.impl.MarkImpl; import com.sap.sailing.domain.base.impl.WaypointImpl; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.MarkType; import com.sap.sailing.domain.common.PassingInstruction; import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; @@ -63,7 +64,7 @@ public class RaceLogCourseDesignChangedEventSerializerTest { factory), new GateDeserializer(factory, new MarkDeserializer(factory)))))); now = MillisecondsTimePoint.now(); - event = new RaceLogCourseDesignChangedEventImpl(now, author, 0, createCourseData()); + event = new RaceLogCourseDesignChangedEventImpl(now, author, 0, createCourseData(), CourseDesignerMode.BY_MARKS); } @Test @@ -75,6 +76,7 @@ public class RaceLogCourseDesignChangedEventSerializerTest { assertEquals(event.getId(), deserializedEvent.getId()); assertEquals(event.getPassId(), deserializedEvent.getPassId()); assertEquals(event.getLogicalTimePoint(), deserializedEvent.getLogicalTimePoint()); + assertEquals(event.getCourseDesignerMode(), deserializedEvent.getCourseDesignerMode()); assertEquals(0, Util.size(event.getInvolvedBoats())); assertEquals(0, Util.size(deserializedEvent.getInvolvedBoats())); diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogEventSerializerTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogEventSerializerTest.java index ea6d4a1f70f..6ba877577eb 100644 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogEventSerializerTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogEventSerializerTest.java @@ -29,6 +29,7 @@ import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogDenoteForTra import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogRegisterCompetitorEventImpl; import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogStartTrackingEventImpl; import com.sap.sailing.domain.base.DomainFactory; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; import com.sap.sailing.domain.common.racelog.RacingProcedureType; import com.sap.sailing.server.gateway.serialization.JsonSerializer; @@ -149,7 +150,7 @@ public class RaceLogEventSerializerTest { @Test public void testChoosesCourseDesignChangedSerializer() { // we use the real event type here because we do not want to re-implement the dispatching. - RaceLogEvent event = new RaceLogCourseDesignChangedEventImpl(null, author, 0, null); + RaceLogEvent event = new RaceLogCourseDesignChangedEventImpl(null, author, 0, null, CourseDesignerMode.ADMIN_CONSOLE); serializer.serialize(event); verify(courseDesignChangedEventSerializer).serialize(event); } diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RaceLogReplicationTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RaceLogReplicationTest.java index 1c639b6bf6e..a4711c69dcb 100755 --- a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RaceLogReplicationTest.java +++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RaceLogReplicationTest.java @@ -33,6 +33,7 @@ import com.sap.sailing.domain.base.impl.CourseDataImpl; import com.sap.sailing.domain.base.impl.MarkImpl; import com.sap.sailing.domain.base.impl.RegattaImpl; import com.sap.sailing.domain.base.impl.WaypointImpl; +import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.MarkType; import com.sap.sailing.domain.common.PassingInstruction; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; @@ -133,11 +134,11 @@ public class RaceLogReplicationTest extends AbstractLogReplicationTest Date: Fri, 22 Apr 2016 17:27:54 +0200 Subject: [PATCH 4/7] when no CourseDesignerMode is specified on a (legacy) RaceLogCourseDesignChangedEvent, use the course as is for backward compatibility Change-Id: I0c883b534e9f8836f3b3d097bb25d7c152b896e7 --- .../race/analyzing/impl/LastPublishedCourseDesignFinder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/LastPublishedCourseDesignFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/LastPublishedCourseDesignFinder.java index ec92eaa3d7c..6f7e08bd104 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/LastPublishedCourseDesignFinder.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/LastPublishedCourseDesignFinder.java @@ -38,7 +38,7 @@ public class LastPublishedCourseDesignFinder extends RaceLogAnalyzer for (RaceLogEvent event : getAllEventsDescending()) { if (event instanceof RaceLogCourseDesignChangedEvent) { RaceLogCourseDesignChangedEvent courseDesignEvent = (RaceLogCourseDesignChangedEvent) event; - if (!onlyCoursesWithValidWaypointList || (courseDesignEvent.getCourseDesignerMode() != null && + if (!onlyCoursesWithValidWaypointList || (courseDesignEvent.getCourseDesignerMode() == null || courseDesignEvent.getCourseDesignerMode().isWaypointSequenceValid())) { return courseDesignEvent.getCourseDesign(); } From 3d5b6d1d6bc39e1d4c268a285d7a5a280e9dc7a9 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 22 Apr 2016 17:33:01 +0200 Subject: [PATCH 5/7] fixing an NPE in the RaceManager app related to a problem with empty selection Change-Id: I0770d0d029e0addf25ed0e94ab5114015164cf8c --- .../sailing/racecommittee/app/ui/activities/RacingActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/RacingActivity.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/RacingActivity.java index a337a8eb182..46205dc3116 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/RacingActivity.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/RacingActivity.java @@ -596,7 +596,7 @@ public class RacingActivity extends SessionActivity implements RaceListCallbacks transaction.remove(extra); } } - if (findViewById(R.id.race_content) != null) { + if (findViewById(R.id.race_content) != null && mSelectedRace != null) { if (mSelectedRace.getStatus() != RaceLogRaceStatus.FINISHING) { content = RaceFlagViewerFragment.newInstance(); } else { From 15df181a2944ddd47adee0b1dd3427b5220edbd0 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 22 Apr 2016 17:59:12 +0200 Subject: [PATCH 6/7] set live leaderboard updater as daemon thread so it doesn't keep VM from stopping Change-Id: Ia619774f50c3f7278def904868b62eb882b03a14 --- .../abstractlog/race/impl/WeakRaceLogChangedVisitor.java | 6 ++++-- .../domain/leaderboard/caching/LiveLeaderboardUpdater.java | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/WeakRaceLogChangedVisitor.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/WeakRaceLogChangedVisitor.java index a056688314a..7940e5f8979 100755 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/WeakRaceLogChangedVisitor.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/WeakRaceLogChangedVisitor.java @@ -27,7 +27,7 @@ public class WeakRaceLogChangedVisitor extends AbstractRaceLogChangedVisitor { private static ReferenceQueue queue = new ReferenceQueue(); private static Map, WeakRaceLogChangedVisitor> referenceToVisitor = new ConcurrentHashMap, WeakRaceLogChangedVisitor>(); static { - new Thread(WeakRaceLogChangedVisitor.class.getSimpleName() + " weak reference cleaner") { + Thread t = new Thread(WeakRaceLogChangedVisitor.class.getSimpleName() + " weak reference cleaner") { @Override public void run() { while (true) { @@ -42,7 +42,9 @@ public class WeakRaceLogChangedVisitor extends AbstractRaceLogChangedVisitor { } } } - }.start(); + }; + t.setDaemon(true); + t.start(); } private final WeakReference listenerRef; diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LiveLeaderboardUpdater.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LiveLeaderboardUpdater.java index 5f2db95e2d0..fca7707a2f4 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LiveLeaderboardUpdater.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LiveLeaderboardUpdater.java @@ -221,6 +221,7 @@ public class LiveLeaderboardUpdater implements Runnable { private synchronized void start() { running = true; thread = new Thread(this, "LiveLeaderboardUpdater for leaderboard "+getLeaderboard().getName()); + thread.setDaemon(true); thread.start(); } From d065302b6d394fb04a9d12f6a4b72da77118aa3a Mon Sep 17 00:00:00 2001 From: "Steffen Tobias Wagner (D059727)" Date: Fri, 22 Apr 2016 21:46:55 +0200 Subject: [PATCH 7/7] fixed bug-3618 by adding utf-8 content-type to servers responses in API --- .../jaxrs/api/CompetitorsResource.java | 4 +-- .../gateway/jaxrs/api/DataMiningResource.java | 4 +-- .../gateway/jaxrs/api/EventsResource.java | 6 ++-- .../jaxrs/api/FileStorageResource.java | 3 +- .../jaxrs/api/LeaderboardGroupsResource.java | 4 +-- .../jaxrs/api/LeaderboardsResource.java | 12 ++++---- .../gateway/jaxrs/api/PingResource.java | 3 +- .../gateway/jaxrs/api/PolarResource.java | 2 +- .../gateway/jaxrs/api/RegattasResource.java | 30 +++++++++---------- .../gateway/jaxrs/api/SearchResource.java | 2 +- 10 files changed, 36 insertions(+), 34 deletions(-) diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CompetitorsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CompetitorsResource.java index 0606a8301d6..17c7ca42125 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CompetitorsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CompetitorsResource.java @@ -80,7 +80,7 @@ public class CompetitorsResource extends AbstractSailingServerResource { .type(MediaType.TEXT_PLAIN).build(); } else { String jsonString = getCompetitorJSON(competitor).toJSONString(); - response = Response.ok(jsonString, MediaType.APPLICATION_JSON).build(); + response = Response.ok(jsonString).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } return response; } @@ -110,7 +110,7 @@ public class CompetitorsResource extends AbstractSailingServerResource { JSONObject teamJson = teamJsonSerializer.serialize(team); String json = teamJson.toJSONString(); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); + return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } /** diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/DataMiningResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/DataMiningResource.java index 472489eaca3..e466f95d472 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/DataMiningResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/DataMiningResource.java @@ -90,7 +90,7 @@ public class DataMiningResource extends AbstractSailingServerResource { } String json = predefinedQueryNames.toJSONString(); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); + return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } // @GET @@ -275,7 +275,7 @@ public class DataMiningResource extends AbstractSailingServerResource { } jsonResult.put("resultUnit", resultUnit != null && !resultUnit.isEmpty() ? resultUnit : "None"); jsonResult.put("results", resultValuesToJSON(result, numberExtractor, resultPlaces)); - response = Response.ok(jsonResult.toJSONString(), MediaType.APPLICATION_JSON).build(); + response = Response.ok(jsonResult.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } catch (NotJsonSerializableException e) { response = getNotSerializableErrorResponse(e.getNotSerializableClass()); } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventsResource.java index 49a8cd60e58..82b7a96edba 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventsResource.java @@ -46,7 +46,7 @@ public class EventsResource extends AbstractSailingServerResource { } } String json = result.toJSONString(); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); + return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } @GET @@ -71,7 +71,7 @@ public class EventsResource extends AbstractSailingServerResource { JSONObject eventJson = eventSerializer.serialize(event); String json = eventJson.toJSONString(); - response = Response.ok(json, MediaType.APPLICATION_JSON).build(); + response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } return response; } @@ -98,7 +98,7 @@ public class EventsResource extends AbstractSailingServerResource { filterByLeaderboard, filterByDayOffset, getService()); JSONObject raceStatesJson = eventRaceStatesSerializer.serialize(new Pair>(event, getService().getLeaderboards().values())); String json = raceStatesJson.toJSONString(); - response = Response.ok(json, MediaType.APPLICATION_JSON).build(); + response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } return response; } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/FileStorageResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/FileStorageResource.java index bb027ede091..0ee8667a9cd 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/FileStorageResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/FileStorageResource.java @@ -13,6 +13,7 @@ import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.Response.Status; @@ -65,7 +66,7 @@ public class FileStorageResource extends AbstractSailingServerResource { getService().getFileStorageManagementService().getActiveFileStorageService() .removeFile(new URI(uri)); result.put("status", Status.OK.name()); - response = Response.ok().entity(result.toJSONString()).build(); + response = Response.ok().entity(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } catch (NoCorrespondingServiceRegisteredException | OperationFailedException | InvalidPropertiesException | URISyntaxException | IOException e) { final String errorMessage = "Could not delete file with URI "+uri+": "+e.getMessage(); diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardGroupsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardGroupsResource.java index 96d6fa865d3..46bd91cf41c 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardGroupsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardGroupsResource.java @@ -52,7 +52,7 @@ public class LeaderboardGroupsResource extends AbstractSailingServerResource { // header option is set to allow communication between two sapsailing servers, especially for // the master data import functionality - return Response.ok(json, MediaType.APPLICATION_JSON).header("Access-Control-Allow-Origin", "*").build(); + return Response.ok(json).header("Access-Control-Allow-Origin", "*").header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } @GET @@ -154,7 +154,7 @@ public class LeaderboardGroupsResource extends AbstractSailingServerResource { } } String json = jsonLeaderboardGroup.toJSONString(); - response = Response.ok(json, MediaType.APPLICATION_JSON).build(); + response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } return response; } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java index 199ec7602e4..1e04efb451c 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java @@ -104,7 +104,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource { jsonLeaderboards.add(leaderboardName); } String json = jsonLeaderboards.toJSONString(); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); + return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } @GET @@ -138,7 +138,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource { jsonLeaderboard.writeJSONString(sw); String json = sw.getBuffer().toString(); - response = Response.ok(json, MediaType.APPLICATION_JSON).build(); + response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } catch (NoWindException | InterruptedException | ExecutionException | IOException e) { response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()) .type(MediaType.TEXT_PLAIN).build(); @@ -509,7 +509,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource { } else { JSONObject json = CompetitorsResource.getCompetitorJSON(competitor); json.put("displayName", leaderboard.getDisplayName(competitor)); - response = Response.ok(json.toJSONString(), MediaType.APPLICATION_JSON).build(); + response = Response.ok(json.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } return response; } @@ -580,7 +580,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource { } JSONObject result = new JSONObject(); result.put("marks", array); - return Response.ok(result.toJSONString(), MediaType.APPLICATION_JSON).build(); + return Response.ok(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } private final MarkJsonSerializer markSerializer = new MarkJsonSerializer(); @@ -671,7 +671,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource { .type(MediaType.TEXT_PLAIN).build(); } else { final JSONObject json = getJsonForColumnFactors(leaderboard, raceColumns); - response = Response.ok(json.toJSONString(), MediaType.APPLICATION_JSON).build(); + response = Response.ok(json.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } } return response; @@ -725,7 +725,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource { } else { raceColumn.setFactor(explicitFactor); final JSONObject json = getJsonForColumnFactors(leaderboard, Collections.singleton(raceColumn)); - response = Response.ok(json.toJSONString(), MediaType.APPLICATION_JSON).build(); + response = Response.ok(json.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } } return response; diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PingResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PingResource.java index cc94de5933a..a8c96f038b9 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PingResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PingResource.java @@ -3,6 +3,7 @@ package com.sap.sailing.server.gateway.jaxrs.api; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource; @@ -12,6 +13,6 @@ public class PingResource extends AbstractSailingServerResource { @GET @Produces("application/json;charset=UTF-8") public Response ping() { - return Response.ok().build(); + return Response.ok().header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PolarResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PolarResource.java index ec832b06767..b60212a857b 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PolarResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PolarResource.java @@ -170,7 +170,7 @@ public class PolarResource extends AbstractSailingServerResource { } finally { maneuverBasedWindEstimationTrackImpl.unlockAfterRead(); } - response = Response.ok(resultAsJson.toJSONString(), MediaType.APPLICATION_JSON).build(); + response = Response.ok(resultAsJson.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } } return response; diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java index e08f2deb2ce..923b5049578 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java @@ -110,7 +110,7 @@ public class RegattasResource extends AbstractSailingServerResource { regattasJson.add(regattaJsonSerializer.serialize(regatta)); } String json = regattasJson.toJSONString(); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); + return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } @GET @@ -128,7 +128,7 @@ public class RegattasResource extends AbstractSailingServerResource { JSONObject serializedRegatta = regattaSerializer.serialize(regatta); String json = serializedRegatta.toJSONString(); - response = Response.ok(json, MediaType.APPLICATION_JSON).build(); + response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } return response; } @@ -157,7 +157,7 @@ public class RegattasResource extends AbstractSailingServerResource { JSONObject serializedRegatta = regattaSerializer.serialize(regatta); String json = serializedRegatta.toJSONString(); - response = Response.ok(json, MediaType.APPLICATION_JSON).build(); + response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } return response; } @@ -273,7 +273,7 @@ public class RegattasResource extends AbstractSailingServerResource { jsonRace.put("competitors", jsonCompetitors); String json = jsonRace.toJSONString(); - response = Response.ok(json, MediaType.APPLICATION_JSON).build(); + response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } } return response; @@ -388,7 +388,7 @@ public class RegattasResource extends AbstractSailingServerResource { String json = jsonRace.toJSONString(); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); + return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } private JSONObject addFixToJsonFixes(JSONArray jsonFixes, GPSFix fix) { @@ -434,7 +434,7 @@ public class RegattasResource extends AbstractSailingServerResource { JSONObject jsonCourse = serializer.serialize(course); String json = jsonCourse.toJSONString(); - response = Response.ok(json, MediaType.APPLICATION_JSON).build(); + response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } } return response; @@ -475,7 +475,7 @@ public class RegattasResource extends AbstractSailingServerResource { JSONObject jsonCourse = serializer.serialize(targetTime); String json = jsonCourse.toJSONString(); - response = Response.ok(json, MediaType.APPLICATION_JSON).build(); + response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } catch (NotEnoughDataHasBeenAddedException | NoWindException e) { response = getNotEnoughDataAvailabeErrorResponse(regattaName, raceName); } @@ -590,7 +590,7 @@ public class RegattasResource extends AbstractSailingServerResource { jsonRaceTimes.put("currentServerTime-ms", now.getTime()); String json = jsonRaceTimes.toJSONString(); - response = Response.ok(json, MediaType.APPLICATION_JSON).build(); + response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } } return response; @@ -623,7 +623,7 @@ public class RegattasResource extends AbstractSailingServerResource { windSourcesAvailable.add(windSourceJson); } } - return Response.ok(windSourcesAvailable.toString(), MediaType.APPLICATION_JSON).build(); + return Response.ok(windSourcesAvailable.toString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } } return response; @@ -681,7 +681,7 @@ public class RegattasResource extends AbstractSailingServerResource { JSONObject jsonWindTracks = serializer.serialize(trackedRace); String json = jsonWindTracks.toJSONString(); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); + return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } } return response; @@ -723,7 +723,7 @@ public class RegattasResource extends AbstractSailingServerResource { JSONObject jsonBearing = serializer.serialize(trackedRace.getDirectionFromStartToNextMark(timePoint) .getFrom()); String json = jsonBearing.toJSONString(); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); + return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } } return response; @@ -750,7 +750,7 @@ public class RegattasResource extends AbstractSailingServerResource { MarkPassingsJsonSerializer serializer = new MarkPassingsJsonSerializer(); JSONObject jsonMarkPassings = serializer.serialize(trackedRace); String json = jsonMarkPassings.toJSONString(); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); + return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } } return response; @@ -778,7 +778,7 @@ public class RegattasResource extends AbstractSailingServerResource { jsonRace.put("id", race.getId().toString()); } String json = jsonRaceResults.toJSONString(); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); + return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } return response; } @@ -925,7 +925,7 @@ public class RegattasResource extends AbstractSailingServerResource { jsonRaceResults.put("legs", jsonLegs); String json = jsonRaceResults.toJSONString(); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); + return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } } return response; @@ -1034,7 +1034,7 @@ public class RegattasResource extends AbstractSailingServerResource { } jsonLiveData.put("competitors", jsonCompetitors); String json = jsonLiveData.toJSONString(); - return Response.ok(json, MediaType.APPLICATION_JSON).build(); + return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } } return response; diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/SearchResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/SearchResource.java index dc926cb8c94..07a4a06de54 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/SearchResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/SearchResource.java @@ -43,6 +43,6 @@ public class SearchResource extends AbstractSailingServerResource { for (LeaderboardSearchResult searchResult : searchResults) { jsonSearchResults.add(serializer.serialize(searchResult)); } - return Response.ok(jsonSearchResults.toJSONString(), MediaType.APPLICATION_JSON).build(); + return Response.ok(jsonSearchResults.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } }