Merge remote-tracking branch 'origin/master' into bug3591_datamining_legtype

This commit is contained in:
fmittag
2016-04-23 14:30:02 +02:00
44 changed files with 219 additions and 89 deletions
@@ -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<CourseDesignerMode> validValues = new ArrayList<CourseDesignerMode>();
for (CourseDesignerMode type : values()) {
@@ -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<Competitor> 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<Competitor> competitors, DBObject dbObject) {
@@ -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,
@@ -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;
}
@@ -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<Util.Pair<ControlPoint, PassingInstruction>> 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);
@@ -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<RaceLog> toRaceLogs, SharedDomainFactory baseDomainFactory,
RacingEventService service) {
CourseBase course = new LastPublishedCourseDesignFinder(fromRaceLog).analyze();
CourseBase course = new LastPublishedCourseDesignFinder(fromRaceLog, /* onlyCoursesWithValidWaypointList */ true).analyze();
final Set<Mark> 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);
}
@@ -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));
@@ -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();
}
@@ -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<CourseBase> {
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<CourseBase>
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;
@@ -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";
}
}
}
@@ -27,7 +27,7 @@ public class WeakRaceLogChangedVisitor extends AbstractRaceLogChangedVisitor {
private static ReferenceQueue<? super RaceLogChangedListener> queue = new ReferenceQueue<RaceLogChangedListener>();
private static Map<Reference<?>, WeakRaceLogChangedVisitor> referenceToVisitor = new ConcurrentHashMap<Reference<?>, 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<RaceLogChangedListener> listenerRef;
@@ -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.
@@ -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
@@ -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() {
@@ -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));
@@ -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();
}
@@ -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) {
@@ -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,9 +79,11 @@ 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);
showWindChart, showCompetitorsChart, showViewStreamlets, showViewStreamletColors, showViewSimulation, autoSelectMedia, defaultMedia, initialDurationAfterRaceStartInReplay);
}
private void createErrorView(String errorMessage, Throwable errorReason, AcceptsOneWidget panel) {
@@ -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<RaceTimePanelSettings> 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<RaceTimePanelSettings> 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;
}
@@ -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<RaceboardDataDTO>() {
@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.
*/
public static 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());
@@ -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);
}
@@ -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;
}
}
@@ -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<com.sap.sse.common.Util.Pair<ControlPointDTO, PassingInstruction>> 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()) {
@@ -22,6 +22,16 @@
</li>
</ul>
<h5 class="articleSubheadline">April 2016</h2>
<ul class="bulletList">
<li>The <tt>/gwt/RaceBoard.html</tt> entry point now accepts an optional parameter "t" in the form
<tt>[[hh:]mm:]ss</tt>, for example <tt>t=12:34</tt> 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 <tt>t=1234</tt> which
makes specifying a time <em>before</em> the start somewhat easier (<tt>t=-123</tt> instead of
<tt>t=-02:-03</tt>).
</li>
</ul>
<h5 class="articleSubheadline">January 2016</h2>
<ul class="bulletList">
<li>Show maneuver markers on the race board by default
@@ -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);
@@ -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);
@@ -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));
}
}
@@ -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<CourseBase> 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;
}
@@ -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()));
@@ -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);
}
@@ -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();
}
/**
@@ -130,7 +130,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();
}
public Response avgSpeedPerCompetitorAndLegType(String regattaName) {
@@ -306,7 +306,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());
}
@@ -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, Iterable<Leaderboard>>(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;
}
@@ -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();
@@ -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;
}
@@ -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;
@@ -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();
}
}
@@ -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;
@@ -120,7 +120,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
@@ -138,7 +138,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;
}
@@ -167,7 +167,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;
}
@@ -283,7 +283,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;
@@ -398,7 +398,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) {
@@ -444,7 +444,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;
@@ -485,7 +485,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);
}
@@ -600,7 +600,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;
@@ -633,7 +633,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;
@@ -691,7 +691,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;
@@ -733,7 +733,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;
@@ -760,7 +760,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;
@@ -788,7 +788,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;
}
@@ -935,7 +935,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;
@@ -1044,7 +1044,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;
@@ -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();
}
}
@@ -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<RaceLog,
final String raceColumnName = "R1";
Regatta masterRegatta = setupRegatta(RegattaImpl.getDefaultName(regattaName, BOAT_CLASS_NAME_49er), seriesName, fleetName, BOAT_CLASS_NAME_49er);
RaceLog masterLog = setupRaceColumn(masterRegatta, seriesName, raceColumnName, fleetName);
raceLogEvent = new RaceLogCourseDesignChangedEventImpl(MillisecondsTimePoint.now(), author, 43, createCourseData());
raceLogEvent = new RaceLogCourseDesignChangedEventImpl(MillisecondsTimePoint.now(), author, 43, createCourseData(), CourseDesignerMode.ADMIN_CONSOLE);
masterLog.add(raceLogEvent);
replicaReplicator.startToReplicateFrom(masterDescriptor);
RaceLog replicaLog = getReplicaLog(seriesName, fleetName, raceColumnName, masterRegatta);
anotherRaceLogEvent = new RaceLogCourseDesignChangedEventImpl(MillisecondsTimePoint.now(), author, 43, createCourseData());
anotherRaceLogEvent = new RaceLogCourseDesignChangedEventImpl(MillisecondsTimePoint.now(), author, 43, createCourseData(), CourseDesignerMode.ADMIN_CONSOLE);
addAndValidateEventIds(masterLog, replicaLog, anotherRaceLogEvent);
compareReplicatedCourseDesignEvent(replicaLog, (RaceLogCourseDesignChangedEvent) anotherRaceLogEvent);
}
@@ -162,11 +163,11 @@ public class RaceLogReplicationTest extends AbstractLogReplicationTest<RaceLog,
final String raceColumnName = "R1";
FlexibleLeaderboard masterLeaderboard = setupFlexibleLeaderboard(leaderboardName);
RaceLog masterLog = setupRaceColumn(leaderboardName, fleetName, raceColumnName);
raceLogEvent = new RaceLogCourseDesignChangedEventImpl(MillisecondsTimePoint.now(), author, 43, createCourseData());
raceLogEvent = new RaceLogCourseDesignChangedEventImpl(MillisecondsTimePoint.now(), author, 43, createCourseData(), CourseDesignerMode.ADMIN_CONSOLE);
masterLog.add(raceLogEvent);
replicaReplicator.startToReplicateFrom(masterDescriptor);
RaceLog replicaLog = getReplicaLog(fleetName, raceColumnName, masterLeaderboard);
anotherRaceLogEvent = new RaceLogCourseDesignChangedEventImpl(MillisecondsTimePoint.now(), author, 43, createCourseData());
anotherRaceLogEvent = new RaceLogCourseDesignChangedEventImpl(MillisecondsTimePoint.now(), author, 43, createCourseData(), CourseDesignerMode.ADMIN_CONSOLE);
addAndValidateEventIds(masterLog, replicaLog, anotherRaceLogEvent);
compareReplicatedCourseDesignEvent(replicaLog, (RaceLogCourseDesignChangedEvent) anotherRaceLogEvent);
}
@@ -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 {
@@ -36,6 +36,7 @@ import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.ControlPointWithTwoMarksImpl;
import com.sap.sailing.domain.base.impl.CourseDataImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
import com.sap.sailing.domain.common.CourseDesignerMode;
import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sailing.racecommittee.app.AppConstants;
import com.sap.sailing.racecommittee.app.R;
@@ -563,7 +564,7 @@ public class CourseFragmentMarks extends CourseFragment implements CourseMarkAda
}
protected void sendCourseDataAndDismiss(CourseBase courseDesign) {
getRaceState().setCourseDesign(MillisecondsTimePoint.now(), courseDesign);
getRaceState().setCourseDesign(MillisecondsTimePoint.now(), courseDesign, CourseDesignerMode.BY_MARKS);
saveChangedCourseDesignInCache(courseDesign);
switch (getArguments().getInt(START_MODE, START_MODE_PRESETUP)) {
case START_MODE_PRESETUP:
@@ -14,6 +14,7 @@ import android.widget.ListView;
import com.sap.sailing.android.shared.util.ViewHelper;
import com.sap.sailing.domain.base.CourseBase;
import com.sap.sailing.domain.base.impl.CourseDataImpl;
import com.sap.sailing.domain.common.CourseDesignerMode;
import com.sap.sailing.racecommittee.app.AppConstants;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.ui.adapters.checked.CheckedItem;
@@ -93,7 +94,7 @@ public class CourseFragmentName extends CourseFragment {
public void handleSelection(String course) {
CourseBase courseLayout = new CourseDataImpl(course);
getRaceState().setCourseDesign(MillisecondsTimePoint.now(), courseLayout);
getRaceState().setCourseDesign(MillisecondsTimePoint.now(), courseLayout, CourseDesignerMode.BY_NAME);
if (getArguments() != null && getArguments().getInt(START_MODE, START_MODE_PRESETUP) == START_MODE_PRESETUP) {
openMainScheduleFragment();